Esempio n. 1
0
    def __init__(self,
                 host='127.0.0.1',
                 port=2087,
                 workspace=getcwd(),
                 use_external_server=False,
                 zmq_in_port=7000,
                 zmq_out_port=7001,
                 server='pyls',
                 server_args=['--tcp']):
        self.req_status = {}
        self.host = host
        self.port = port
        self.workspace = workspace
        # self.request_seq = 1

        self.server = None
        self.is_local_server_running = not use_external_server
        if not use_external_server:
            LOGGER.info('Starting server: {0} {1} on {2}:{3}'.format(
                server, ' '.join(server_args), self.host, self.port))
            exec_line = [server] + server_args
            LOGGER.info(' '.join(exec_line))

            self.server = subprocess.Popen(exec_line,
                                           stdout=subprocess.PIPE,
                                           stderr=subprocess.PIPE)

        LOGGER.info('Connecting to language server at {0}:{1}'.format(
            self.host, self.port))
        connected = False

        initial_time = time.time()
        while not connected:
            try:
                self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.socket.connect((self.host, int(self.port)))
                connected = True
            except Exception:
                pass

            if time.time() - initial_time > self.MAX_TIMEOUT_TIME:
                break

        if not connected:
            LOGGER.error("The client was unable to establish a connection "
                         "with the language server, terminating process...")
            raise Exception('Error!')

        self.socket.setblocking(True)

        # LOGGER.info('Initializing server connection...')
        # self.__initialize()

        LOGGER.info('Starting ZMQ connection...')
        self.context = zmq.Context()
        self.zmq_in_socket = self.context.socket(zmq.PAIR)
        self.zmq_in_socket.connect("tcp://localhost:{0}".format(zmq_in_port))
        self.zmq_out_socket = self.context.socket(zmq.PAIR)
        self.zmq_out_socket.connect("tcp://localhost:{0}".format(zmq_out_port))
        self.zmq_out_socket.send_pyobj({
            'id': -1,
            'method': 'server_ready',
            'params': {}
        })

        LOGGER.info('Creating consumer Thread...')
        self.reading_thread = IncomingMessageThread()
        self.reading_thread.initialize(self.socket, self.zmq_out_socket,
                                       self.req_status)
Esempio n. 2
0
class LanguageServerClient:
    """Implementation of a v3.0 compilant language server client."""
    CONTENT_LENGTH = 'Content-Length: {0}\r\n\r\n'
    MAX_TIMEOUT_TIME = 5000

    def __init__(self,
                 host='127.0.0.1',
                 port=2087,
                 workspace=getcwd(),
                 use_external_server=False,
                 zmq_in_port=7000,
                 zmq_out_port=7001,
                 server='pyls',
                 server_args=['--tcp']):
        self.req_status = {}
        self.host = host
        self.port = port
        self.workspace = workspace
        # self.request_seq = 1

        self.server = None
        self.is_local_server_running = not use_external_server
        if not use_external_server:
            LOGGER.info('Starting server: {0} {1} on {2}:{3}'.format(
                server, ' '.join(server_args), self.host, self.port))
            exec_line = [server] + server_args
            LOGGER.info(' '.join(exec_line))

            self.server = subprocess.Popen(exec_line,
                                           stdout=subprocess.PIPE,
                                           stderr=subprocess.PIPE)

        LOGGER.info('Connecting to language server at {0}:{1}'.format(
            self.host, self.port))
        connected = False

        initial_time = time.time()
        while not connected:
            try:
                self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.socket.connect((self.host, int(self.port)))
                connected = True
            except Exception:
                pass

            if time.time() - initial_time > self.MAX_TIMEOUT_TIME:
                break

        if not connected:
            LOGGER.error("The client was unable to establish a connection "
                         "with the language server, terminating process...")
            raise Exception('Error!')

        self.socket.setblocking(True)

        # LOGGER.info('Initializing server connection...')
        # self.__initialize()

        LOGGER.info('Starting ZMQ connection...')
        self.context = zmq.Context()
        self.zmq_in_socket = self.context.socket(zmq.PAIR)
        self.zmq_in_socket.connect("tcp://localhost:{0}".format(zmq_in_port))
        self.zmq_out_socket = self.context.socket(zmq.PAIR)
        self.zmq_out_socket.connect("tcp://localhost:{0}".format(zmq_out_port))
        self.zmq_out_socket.send_pyobj({
            'id': -1,
            'method': 'server_ready',
            'params': {}
        })

        LOGGER.info('Creating consumer Thread...')
        self.reading_thread = IncomingMessageThread()
        self.reading_thread.initialize(self.socket, self.zmq_out_socket,
                                       self.req_status)

    def start(self):
        LOGGER.info('Ready to recieve/attend requests and responses!')
        self.reading_thread.start()

    def stop(self):
        # LOGGER.info('Sending shutdown instruction to server')
        # self.shutdown()
        # LOGGER.info('Sending exit instruction to server')
        # try:
        # self.exit()
        # except ConnectionAbortedError:
        # pass
        LOGGER.info('Closing TCP socket...')
        self.socket.close()
        if self.is_local_server_running:
            LOGGER.info('Closing language server process...')
            self.server.terminate()
        LOGGER.info('Closing consumer thread...')
        self.reading_thread.stop()
        LOGGER.debug('Joining thread...')
        self.reading_thread.join()
        LOGGER.debug('Exit routine should be complete')

    def listen(self):
        events = self.zmq_in_socket.poll(TIMEOUT)
        # requests = []
        while events > 0:
            client_request = self.zmq_in_socket.recv_pyobj()
            LOGGER.debug("Client Event: {0}".format(client_request))
            server_request = self.__compose_request(client_request['id'],
                                                    client_request['method'],
                                                    client_request['params'])
            self.__send_request(server_request)
            # self.zmq_socket.send_pyobj({'a': 'b'})
            events -= 1

    def __compose_request(self, id, method, params):
        request = {
            "jsonrpc": "2.0",
            "id": id,
            "method": method,
            "params": params
        }
        return request

    def __send_request(self, request):
        json_req = json.dumps(request)
        content = bytes(json_req.encode('utf-8'))
        content_length = len(content)

        LOGGER.debug('Sending request of type: {0}'.format(request['method']))
        LOGGER.debug(json_req)

        content_length = self.CONTENT_LENGTH.format(content_length).encode(
            'utf-8')
        self.socket.send(bytes(content_length))
        self.socket.send(content)