Sun, 17 Sep 2017 17:03:16 +0200
Implemented the distributed History dialog and moved the Undo/Redo functions to this dialog.
# -*- coding: utf-8 -*- # Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the JSON based client base class. """ from __future__ import unicode_literals try: bytes = unicode import StringIO as io # __IGNORE_EXCEPTION__ except NameError: import io # __IGNORE_WARNING__ import sys import socket import select import traceback import json class JsonClient(object): """ Class implementing the JSON based client base class. """ def __init__(self, host, port): """ Constructor @param host ip address the background service is listening @type str @param port port of the background service @type int """ self.__exitClient = False self.__connection = socket.create_connection((host, port)) def sendJson(self, command, params): """ Public method to send a single refactoring command to the server. @param command command name to be sent @type str @param params dictionary of named parameters for the command @type dict """ commandDict = { "jsonrpc": "2.0", "method": command, "params": params, } cmd = json.dumps(commandDict) + '\n' self.__connection.sendall(cmd.encode('utf8', 'backslashreplace')) def __receiveJson(self): """ Private method to receive a JSON encode command and data from the server. """ line = self.__connection.recv(1024 * 1024, socket.MSG_PEEK) # 1MB buffer eol = line.find(b'\n') if eol >= 0: size = eol + 1 # Now we know how big the line is, read it for real. line = self.__connection.recv(size).decode( 'utf8', 'backslashreplace') try: commandDict = json.loads(line.strip()) except (TypeError, ValueError) as err: self.sendJson("ClientException", { "ExceptionType": "ProtocolError", "ExceptionValue": str(err), "ProtocolData": line.strip(), }) return method = commandDict["method"] params = commandDict["params"] if method == "Exit": self.__exitClient = True else: self.handleCall(method, params) def handleCall(self, method, params): """ Public method to handle a method call from the server. Note: This is an empty implementation that must be overridden in derived classes. @param method requested method name @type str @param params dictionary with method specific parameters @type dict """ pass def run(self): """ Public method implementing the main loop of the client. """ try: while True: try: rrdy, wrdy, xrdy = select.select( [self.__connection], [], []) except (select.error, KeyboardInterrupt, socket.error): # just carry on continue if self.__connection in rrdy: self.__receiveJson() if self.__exitClient: break except Exception: exctype, excval, exctb = sys.exc_info() tbinfofile = io.StringIO() traceback.print_tb(exctb, None, tbinfofile) tbinfofile.seek(0) tbinfo = tbinfofile.read() del exctb self.sendJson("ClientException", { "ExceptionType": str(exctype), "ExceptionValue": str(excval), "Traceback": tbinfo, }) # Give time to process latest response on server side self.__connection.shutdown(socket.SHUT_RDWR) self.__connection.close() def poll(self): """ Public method to check and receive one message (if available). """ try: rrdy, wrdy, xrdy = select.select([self.__connection], [], [], 0) if self.__connection in rrdy: self.__receiveJson() except (select.error, KeyboardInterrupt, socket.error): # just ignore these return except Exception: exctype, excval, exctb = sys.exc_info() tbinfofile = io.StringIO() traceback.print_tb(exctb, None, tbinfofile) tbinfofile.seek(0) tbinfo = tbinfofile.read() del exctb self.sendJson("ClientException", { "ExceptionType": str(exctype), "ExceptionValue": str(excval), "Traceback": tbinfo, })