--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RefactoringRope/RefactoringClient.py Mon Sep 11 19:15:44 2017 +0200 @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the refactoring client interface to rope. +""" + +from __future__ import unicode_literals + +import sys +import os + +sys.path.insert(0, os.path.dirname(__file__)) +if sys.version_info[0] >= 3: + path = os.path.join(os.path.dirname(__file__), 'rope_py3') +else: + path = os.path.join(os.path.dirname(__file__), 'rope_py2') +sys.path.insert(0, path) + +try: + bytes = unicode + import StringIO as io # __IGNORE_EXCEPTION__ +except NameError: + import io # __IGNORE_WARNING__ + +import socket +import select +import traceback +import time +import json + +import rope.base.project + + +class RefactoringClient(object): + """ + Class implementing the refactoring client interface to rope. + """ + def __init__(self, host, port, projectPath): + """ + Constructor + + @param host ip address the background service is listening + @type str + @param port port of the background service + @type int + @param projectPath path to the project + @type str + """ + self.__connection = socket.create_connection((host, port)) + + self.__projectpath = projectPath + self.__project = rope.base.project.Project( + self.__projectpath)#, fscommands=self.__fsCommands) + + def __processJson(self, jsonStr): + """ + Public method to handle a command serialized as a JSON string. + + @param jsonStr string containing the command received from the IDE + @type str + """ + try: + commandDict = json.loads(jsonStr.strip()) + except (TypeError, ValueError) as err: + self.__sendJson("ClientException", { + "ExceptionType": "ProtocolError", + "ExceptionValue": str(err), + "ProtocolData": jsonStr.strip(), + }) + return + + method = commandDict["method"] + params = commandDict["params"] + if "filename" in params and sys.version_info[0] == 2: + params["filename"] = params["filename"].encode( + sys.getfilesystemencoding()) + + if method == "ping": + self.__sendJson("pong", {}) + + def __sendJson(self, command, params): + """ + Private method to send a single refactoring command to the client. + + @param command command name to be sent + @type str + @param params dictionary of named parameters for the command + @type dict + """ + import json + + 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) # 1M 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') + self.__processJson(line) + + def run(self): + """ + Public method implementing the main loop of the client. + """ + try: + while True: + try: + rrdy, wrdy, xrdy = select.select( + [self.__connection], [self.__connection], []) + except (select.error, KeyboardInterrupt, socket.error): + # just carry on + continue + + if self.__connection in rrdy: + self.__receiveJson() +## +## if self.__connection in wrdy: +## self.__connection.flush() + + 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 + time.sleep(0.5) + self.__connection.shutdown(socket.SHUT_RDWR) + self.__connection.close() + +if __name__ == '__main__': + if len(sys.argv) != 4: + print('Host, port and project path parameters are missing. Abort.') + sys.exit(1) + + host, port, projectPath = sys.argv[1:] + client = RefactoringClient(host, int(port), projectPath) + # Start the main loop + client.run() + +# +# eflag: noqa = M801