RefactoringRope/JsonClient.py

branch
server_client_variant
changeset 163
6a9e7b37a18b
child 164
121d426d4ed7
equal deleted inserted replaced
162:55eaaed9d590 163:6a9e7b37a18b
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the JSON based client base class.
8 """
9
10 from __future__ import unicode_literals
11 try:
12 bytes = unicode
13 import StringIO as io # __IGNORE_EXCEPTION__
14 except NameError:
15 import io # __IGNORE_WARNING__
16
17 import sys
18 import socket
19 import select
20 import traceback
21 import time
22 import json
23
24
25 class JsonClient(object):
26 """
27 Class implementing the JSON based client base class.
28 """
29 def __init__(self, host, port):
30 """
31 Constructor
32
33 @param host ip address the background service is listening
34 @type str
35 @param port port of the background service
36 @type int
37 """
38 self.__connection = socket.create_connection((host, port))
39
40 def sendJson(self, command, params):
41 """
42 Public method to send a single refactoring command to the server.
43
44 @param command command name to be sent
45 @type str
46 @param params dictionary of named parameters for the command
47 @type dict
48 """
49 commandDict = {
50 "jsonrpc": "2.0",
51 "method": command,
52 "params": params,
53 }
54 cmd = json.dumps(commandDict) + '\n'
55 self.__connection.sendall(cmd.encode('utf8', 'backslashreplace'))
56
57 def __receiveJson(self):
58 """
59 Private method to receive a JSON encode command and data from the
60 server.
61 """
62 line = self.__connection.recv(1024 * 1024, socket.MSG_PEEK) # 1M buffer
63
64 eol = line.find(b'\n')
65
66 if eol >= 0:
67 size = eol + 1
68
69 # Now we know how big the line is, read it for real.
70 line = self.__connection.recv(size).decode(
71 'utf8', 'backslashreplace')
72 try:
73 commandDict = json.loads(line.strip())
74 except (TypeError, ValueError) as err:
75 self.sendJson("ClientException", {
76 "ExceptionType": "ProtocolError",
77 "ExceptionValue": str(err),
78 "ProtocolData": line.strip(),
79 })
80 return
81
82 method = commandDict["method"]
83 params = commandDict["params"]
84 self.handleCall(method, params)
85
86 def handleCall(self, method, params):
87 """
88 Public method to handle a method call from the server.
89
90 Note: This is an empty implementation that must be overridden in
91 derived classes.
92
93 @param method requested method name
94 @type str
95 @param params dictionary with method specific parameters
96 @type dict
97 """
98 pass
99
100 def run(self):
101 """
102 Public method implementing the main loop of the client.
103 """
104 try:
105 while True:
106 try:
107 rrdy, wrdy, xrdy = select.select(
108 [self.__connection], [], [])
109 except (select.error, KeyboardInterrupt, socket.error):
110 # just carry on
111 continue
112
113 if self.__connection in rrdy:
114 self.__receiveJson()
115
116 except Exception:
117 exctype, excval, exctb = sys.exc_info()
118 tbinfofile = io.StringIO()
119 traceback.print_tb(exctb, None, tbinfofile)
120 tbinfofile.seek(0)
121 tbinfo = tbinfofile.read()
122 del exctb
123 self.sendJson("ClientException", {
124 "ExceptionType": str(exctype),
125 "ExceptionValue": str(excval),
126 "Traceback": tbinfo,
127 })
128
129 # Give time to process latest response on server side
130 time.sleep(0.5)
131 self.__connection.shutdown(socket.SHUT_RDWR)
132 self.__connection.close()

eric ide

mercurial