--- a/RefactoringRope/JsonServer.py Sun Sep 24 17:10:48 2017 +0200 +++ b/RefactoringRope/JsonServer.py Sun Sep 24 19:27:30 2017 +0200 @@ -24,17 +24,24 @@ """ Class implementing the JSON based server base class. """ - def __init__(self, parent=None): + def __init__(self, multiplex=False, parent=None): """ Constructor + @param multiplex flag indicating a multiplexing server + @type bool @param parent parent object @type QObject """ super(JsonServer, self).__init__(parent) - self.__clientProcess = None - self.__connection = None + self.__multiplex = multiplex + if self.__multiplex: + self.__clientProcesses = {} + self.__connections = {} + else: + self.__clientProcess = None + self.__connection = None # setup the network interface networkInterface = Preferences.getDebugger("NetworkInterface") @@ -56,39 +63,67 @@ @pyqtSlot() def __handleNewConnection(self): """ - Private slot for new incomming connections from the refactoring client. + Private slot for new incoming connections from a client. """ - if self.__connection is not None: - self.__connection.close() - self.__connection = None - connection = self.nextPendingConnection() if not connection.isValid(): return - self.__connection = connection - connection.readyRead.connect(self.__receiveJson) - connection.disconnected.connect(self.__handleDisconnect) + if self.__multiplex: + if not connection.waitForReadyRead(3000): + return + idString = bytes(connection.readLine()).decode( + "utf-8", 'backslashreplace') + if idString in self.__connections: + self.__connections[id].close() + self.__connections[id] = connection + else: + idString = "" + if self.__connection is not None: + self.__connection.close() + + self.__connection = connection + + connection.readyRead.connect( + lambda: self.__receiveJson(idString)) + connection.disconnected.connect( + lambda: self.__handleDisconnect(idString)) self.sendJson("GetConfig", {}) @pyqtSlot() - def __handleDisconnect(self): + def __handleDisconnect(self, idString): """ - Private slot handling a disconnect of the refactoring client. + Private slot handling a disconnect of the client. + + @param idString id of the connection been disconnected + @type str """ - if self.__connection is not None: - self.__connection.close() - - self.__connection = None + if idString: + if idString in self.__connections: + self.__connections[idString].close() + del self.__connections[id] + else: + if self.__connection is not None: + self.__connection.close() + + self.__connection = None @pyqtSlot() - def __receiveJson(self): + def __receiveJson(self, idString): """ Private slot handling received data from the client. + + @param idString id of the connection been disconnected + @type str """ - while self.__connection and self.__connection.canReadLine(): - data = self.__connection.readLine() + if idString: + connection = self.__connections[idString] + else: + connection = self.__connection + + while connection and connection.canReadLine(): + data = connection.readLine() jsonLine = bytes(data).decode("utf-8", 'backslashreplace') ## print("JSON Server: ", jsonLine) ##debug @@ -129,9 +164,9 @@ """ pass - def sendJson(self, command, params, flush=False): + def sendJson(self, command, params, flush=False, idString=""): """ - Public method to send a single refactoring command to the client. + Public method to send a single command to a client. @param command command name to be sent @type str @@ -139,6 +174,8 @@ @type dict @param flush flag indicating to flush the data to the socket @type bool + @param idString id of the connection to send data to + @type str """ commandDict = { "jsonrpc": "2.0", @@ -147,20 +184,27 @@ } cmd = json.dumps(commandDict) + '\n' - if self.__connection is not None: - self.__connection.write(cmd.encode('utf8', 'backslashreplace')) + if idString: + connection = self.__connections[idString] + else: + connection = self.__connection + + if connection is not None: + connection.write(cmd.encode('utf8', 'backslashreplace')) if flush: - self.__connection.flush() + connection.flush() - def startClient(self, interpreter, clientScript, clientArgs): + def startClient(self, interpreter, clientScript, clientArgs, idString=""): """ - Public method to start the client process. + Public method to start a client process. @param interpreter interpreter to be used for the client @type str @param clientScript path to the client script @type str @param clientArgs list of arguments for the client + @param idString id of the client to be started + @type str @return flag indicating a successful client start @rtype bool """ @@ -175,19 +219,33 @@ if not proc.waitForStarted(10000): proc = None - self.__clientProcess = proc + if idString: + self.__clientProcesses[idString] = proc + else: + self.__clientProcess = proc return proc is not None - def stopClient(self): + def stopClient(self, idString=""): """ - Public method to stop the client process. + Public method to stop a client process. + + @param idString id of the client to be stopped + @type str """ - self.sendJson("Exit", {}, flush=True) + self.sendJson("Exit", {}, flush=True, idString=idString) - if self.__connection is not None: - self.__connection.waitForDisconnected() + if idString: + connection = self.__connections[idString] + else: + connection = self.__connection + if connection is not None: + connection.waitForDisconnected() - if self.__clientProcess is not None: - self.__clientProcess.close() - self.__clientProcess = None + if idString: + self .__clientProcesses[idString].close() + del self.__clientProcesses[idString] + else: + if self.__clientProcess is not None: + self.__clientProcess.close() + self.__clientProcess = None