RefactoringRope/RefactoringClient.py

branch
server_client_variant
changeset 161
f5d6fb1a009b
child 162
55eaaed9d590
--- /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

eric ide

mercurial