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 |