RefactoringRope/JsonServer.py

branch
server_client_variant
changeset 192
20950ed6b384
parent 189
2711fdd91925
child 194
5c297b473425
equal deleted inserted replaced
191:2af42804bca2 192:20950ed6b384
22 22
23 class JsonServer(QTcpServer): 23 class JsonServer(QTcpServer):
24 """ 24 """
25 Class implementing the JSON based server base class. 25 Class implementing the JSON based server base class.
26 """ 26 """
27 def __init__(self, parent=None): 27 def __init__(self, multiplex=False, parent=None):
28 """ 28 """
29 Constructor 29 Constructor
30 30
31 @param multiplex flag indicating a multiplexing server
32 @type bool
31 @param parent parent object 33 @param parent parent object
32 @type QObject 34 @type QObject
33 """ 35 """
34 super(JsonServer, self).__init__(parent) 36 super(JsonServer, self).__init__(parent)
35 37
36 self.__clientProcess = None 38 self.__multiplex = multiplex
37 self.__connection = None 39 if self.__multiplex:
40 self.__clientProcesses = {}
41 self.__connections = {}
42 else:
43 self.__clientProcess = None
44 self.__connection = None
38 45
39 # setup the network interface 46 # setup the network interface
40 networkInterface = Preferences.getDebugger("NetworkInterface") 47 networkInterface = Preferences.getDebugger("NetworkInterface")
41 if networkInterface == "all" or '.' in networkInterface: 48 if networkInterface == "all" or '.' in networkInterface:
42 # IPv4 49 # IPv4
54 # __IGNORE_WARNING__ 61 # __IGNORE_WARNING__
55 62
56 @pyqtSlot() 63 @pyqtSlot()
57 def __handleNewConnection(self): 64 def __handleNewConnection(self):
58 """ 65 """
59 Private slot for new incomming connections from the refactoring client. 66 Private slot for new incoming connections from a client.
60 """ 67 """
61 if self.__connection is not None:
62 self.__connection.close()
63 self.__connection = None
64
65 connection = self.nextPendingConnection() 68 connection = self.nextPendingConnection()
66 if not connection.isValid(): 69 if not connection.isValid():
67 return 70 return
68 71
69 self.__connection = connection 72 if self.__multiplex:
70 connection.readyRead.connect(self.__receiveJson) 73 if not connection.waitForReadyRead(3000):
71 connection.disconnected.connect(self.__handleDisconnect) 74 return
75 idString = bytes(connection.readLine()).decode(
76 "utf-8", 'backslashreplace')
77 if idString in self.__connections:
78 self.__connections[id].close()
79 self.__connections[id] = connection
80 else:
81 idString = ""
82 if self.__connection is not None:
83 self.__connection.close()
84
85 self.__connection = connection
86
87 connection.readyRead.connect(
88 lambda: self.__receiveJson(idString))
89 connection.disconnected.connect(
90 lambda: self.__handleDisconnect(idString))
72 91
73 self.sendJson("GetConfig", {}) 92 self.sendJson("GetConfig", {})
74 93
75 @pyqtSlot() 94 @pyqtSlot()
76 def __handleDisconnect(self): 95 def __handleDisconnect(self, idString):
77 """ 96 """
78 Private slot handling a disconnect of the refactoring client. 97 Private slot handling a disconnect of the client.
79 """ 98
80 if self.__connection is not None: 99 @param idString id of the connection been disconnected
81 self.__connection.close() 100 @type str
82 101 """
83 self.__connection = None 102 if idString:
103 if idString in self.__connections:
104 self.__connections[idString].close()
105 del self.__connections[id]
106 else:
107 if self.__connection is not None:
108 self.__connection.close()
109
110 self.__connection = None
84 111
85 @pyqtSlot() 112 @pyqtSlot()
86 def __receiveJson(self): 113 def __receiveJson(self, idString):
87 """ 114 """
88 Private slot handling received data from the client. 115 Private slot handling received data from the client.
89 """ 116
90 while self.__connection and self.__connection.canReadLine(): 117 @param idString id of the connection been disconnected
91 data = self.__connection.readLine() 118 @type str
119 """
120 if idString:
121 connection = self.__connections[idString]
122 else:
123 connection = self.__connection
124
125 while connection and connection.canReadLine():
126 data = connection.readLine()
92 jsonLine = bytes(data).decode("utf-8", 'backslashreplace') 127 jsonLine = bytes(data).decode("utf-8", 'backslashreplace')
93 128
94 ## print("JSON Server: ", jsonLine) ##debug 129 ## print("JSON Server: ", jsonLine) ##debug
95 130
96 try: 131 try:
127 @param params dictionary with method specific parameters 162 @param params dictionary with method specific parameters
128 @type dict 163 @type dict
129 """ 164 """
130 pass 165 pass
131 166
132 def sendJson(self, command, params, flush=False): 167 def sendJson(self, command, params, flush=False, idString=""):
133 """ 168 """
134 Public method to send a single refactoring command to the client. 169 Public method to send a single command to a client.
135 170
136 @param command command name to be sent 171 @param command command name to be sent
137 @type str 172 @type str
138 @param params dictionary of named parameters for the command 173 @param params dictionary of named parameters for the command
139 @type dict 174 @type dict
140 @param flush flag indicating to flush the data to the socket 175 @param flush flag indicating to flush the data to the socket
141 @type bool 176 @type bool
177 @param idString id of the connection to send data to
178 @type str
142 """ 179 """
143 commandDict = { 180 commandDict = {
144 "jsonrpc": "2.0", 181 "jsonrpc": "2.0",
145 "method": command, 182 "method": command,
146 "params": params, 183 "params": params,
147 } 184 }
148 cmd = json.dumps(commandDict) + '\n' 185 cmd = json.dumps(commandDict) + '\n'
149 186
150 if self.__connection is not None: 187 if idString:
151 self.__connection.write(cmd.encode('utf8', 'backslashreplace')) 188 connection = self.__connections[idString]
189 else:
190 connection = self.__connection
191
192 if connection is not None:
193 connection.write(cmd.encode('utf8', 'backslashreplace'))
152 if flush: 194 if flush:
153 self.__connection.flush() 195 connection.flush()
154 196
155 def startClient(self, interpreter, clientScript, clientArgs): 197 def startClient(self, interpreter, clientScript, clientArgs, idString=""):
156 """ 198 """
157 Public method to start the client process. 199 Public method to start a client process.
158 200
159 @param interpreter interpreter to be used for the client 201 @param interpreter interpreter to be used for the client
160 @type str 202 @type str
161 @param clientScript path to the client script 203 @param clientScript path to the client script
162 @type str 204 @type str
163 @param clientArgs list of arguments for the client 205 @param clientArgs list of arguments for the client
206 @param idString id of the client to be started
207 @type str
164 @return flag indicating a successful client start 208 @return flag indicating a successful client start
165 @rtype bool 209 @rtype bool
166 """ 210 """
167 if interpreter == "" or not Utilities.isinpath(interpreter): 211 if interpreter == "" or not Utilities.isinpath(interpreter):
168 return False 212 return False
173 args.extend(clientArgs) 217 args.extend(clientArgs)
174 proc.start(interpreter, args) 218 proc.start(interpreter, args)
175 if not proc.waitForStarted(10000): 219 if not proc.waitForStarted(10000):
176 proc = None 220 proc = None
177 221
178 self.__clientProcess = proc 222 if idString:
223 self.__clientProcesses[idString] = proc
224 else:
225 self.__clientProcess = proc
179 226
180 return proc is not None 227 return proc is not None
181 228
182 def stopClient(self): 229 def stopClient(self, idString=""):
183 """ 230 """
184 Public method to stop the client process. 231 Public method to stop a client process.
185 """ 232
186 self.sendJson("Exit", {}, flush=True) 233 @param idString id of the client to be stopped
187 234 @type str
188 if self.__connection is not None: 235 """
189 self.__connection.waitForDisconnected() 236 self.sendJson("Exit", {}, flush=True, idString=idString)
190 237
191 if self.__clientProcess is not None: 238 if idString:
192 self.__clientProcess.close() 239 connection = self.__connections[idString]
193 self.__clientProcess = None 240 else:
241 connection = self.__connection
242 if connection is not None:
243 connection.waitForDisconnected()
244
245 if idString:
246 self .__clientProcesses[idString].close()
247 del self.__clientProcesses[idString]
248 else:
249 if self.__clientProcess is not None:
250 self.__clientProcess.close()
251 self.__clientProcess = None

eric ide

mercurial