コード例 #1
0
ファイル: server.py プロジェクト: bestdpf/aiorpc
async def serve(reader, writer):
    """Serve function.
    Don't use this outside asyncio.start_server.
    """
    global _unpack_encoding, _unpack_params
    _logger.debug('enter serve: {}'.format(writer.get_extra_info('peername')))

    conn = Connection(reader, writer,
                      msgpack.Unpacker(encoding=_unpack_encoding, **_unpack_params))

    while not conn.is_closed():
        req = None
        try:
            req = await conn.recvall()
        except (RPCIOError, ConnectionError) as ie:
            print(f'server io error')
            break
        except Exception as e:
            print(f'unknow exception')
            import traceback
            traceback.print_exc()
            conn.reader.set_exception(e)
            raise e

        if not isinstance(req, tuple):
            try:
                await _send_error(conn, "Invalid protocol", -1)
                # skip the rest of iteration code after sending error
                continue

            except Exception as e:
                _logger.error("Error when receiving req: {}".format(str(e)))
        asyncio.create_task(handle_request(conn, req))
コード例 #2
0
ファイル: client.py プロジェクト: markuspi/aiorpc
 async def _open_connection(self):
     _logger.debug("connect to %s:%s...", *self.getpeername())
     if self._host:
         reader, writer = await asyncio.open_connection(self._host, self._port, loop=self._loop)
     else:
         reader, writer = await asyncio.open_unix_connection(self._path, loop=self._loop)
     self._conn = Connection(reader, writer,
                             msgpack.Unpacker(raw=False,
                                              **self._unpack_params))
     _logger.debug("Connection to %s:%s established", *self.getpeername())
コード例 #3
0
ファイル: client.py プロジェクト: pyneda/aiorpc
 async def _open_connection(self):
     _logger.debug("connect to {}:{}...".format(self._host, self._port))
     reader, writer = await asyncio.open_connection(self._host,
                                                    self._port,
                                                    loop=self._loop)
     self._conn = Connection(
         reader, writer,
         msgpack.Unpacker(encoding=self._unpack_encoding,
                          **self._unpack_params))
     _logger.debug("Connection to {}:{} established".format(
         self._host, self._port))
コード例 #4
0
ファイル: server.py プロジェクト: pyneda/aiorpc
async def serve(reader, writer):
    """Serve function.
    Don't use this outside asyncio.start_server.
    """
    global _unpack_encoding, _unpack_params
    _logger.debug('enter serve: {}'.format(writer.get_extra_info('peername')))

    conn = Connection(
        reader, writer,
        msgpack.Unpacker(encoding=_unpack_encoding, **_unpack_params))
    while not conn.is_closed():
        req = None
        try:
            req = await conn.recvall(_timeout)
        except asyncio.TimeoutError as te:
            conn.reader.set_exception(te)
        except IOError as ie:
            break
        except Exception as e:
            conn.reader.set_exception(e)
            raise e

        if type(req) != tuple:
            try:
                await _send_error(conn, "Invalid protocol", -1)
            except Exception as e:
                _logger.error("Error when receiving req: {}".format(str(e)))
                return

        method = None
        msg_id = None
        args = None
        try:
            _logger.debug('parsing req: {}'.format(str(req)))
            (msg_id, method, args) = _parse_request(req)
            _logger.debug('parsing completed: {}'.format(str(req)))
        except Exception as e:
            _logger.error("Exception {} raised when _parse_request {}".format(
                str(e), req))

        try:
            _logger.debug('calling method: {}'.format(str(method)))
            ret = method.__call__(*args)
            if asyncio.iscoroutine(ret):
                _logger.debug("start to wait_for")
                ret = await asyncio.wait_for(ret, _timeout)
            _logger.debug('calling {} completed. result: {}'.format(
                str(method), str(ret)))
        except Exception as e:
            await _send_error(conn, str(e), msg_id)
        else:
            _logger.debug('sending result: {}'.format(str(ret)))
            await _send_result(conn, ret, msg_id)
            _logger.debug('sending result {} completed'.format(str(ret)))
コード例 #5
0
ファイル: client.py プロジェクト: wiltonlazary/aiorpc
    async def call(self, method, *args):
        """Calls a RPC method.

        :param str method: Method name.
        :param args: Method arguments.
        """

        _logger.debug('creating request')
        req = self._create_request(method, args)

        if self._conn is None:
            _logger.debug("connect to {}:{}...".format(self._host, self._port))
            reader, writer = await asyncio.open_connection(self._host,
                                                           self._port,
                                                           loop=self._loop)
            self._conn = Connection(
                reader, writer,
                msgpack.Unpacker(encoding=self._unpack_encoding,
                                 **self._unpack_params))
            _logger.debug("Connection to {}:{} established".format(
                self._host, self._port))

        try:
            _logger.debug('Sending req: {}'.format(req))
            await self._conn.sendall(req, self._timeout)
            _logger.debug('Sending complete')
        except asyncio.TimeoutError as te:
            _logger.error("Write request to {}:{} timeout".format(
                self._host, self._port))
            raise te
        except Exception as e:
            raise e

        response = None
        try:
            _logger.debug('receiving result from server')
            response = await self._conn.recvall(self._timeout)
            _logger.debug('receiving result completed')
        except asyncio.TimeoutError as te:
            _logger.error("Read request to {}:{} timeout".format(
                self._host, self._port))
            self._conn.reader.set_exception(te)
            raise te
        except Exception as e:
            self._conn.reader.set_exception(e)
            raise e

        if response is None:
            raise IOError("Connection closed")

        if type(response) != tuple:
            logging.debug(
                'Protocol error, received unexpected data: {}'.format(
                    response))
            raise RPCProtocolError('Invalid protocol')

        return self._parse_response(response)
コード例 #6
0
ファイル: client.py プロジェクト: dmig/aiorpc
class RPCClient:
    """RPC client.

    Usage:
        >>> from aiorpc.client import RPCClient
        >>> client = RPCClient('127.0.0.1', 6000)
        >>> import asyncio
        >>> loop = asyncio.get_event_loop()
        >>> loop.run_until_complete(client.call('sum', 1, 2))

    :param str host: Hostname.
    :param int port: Port number.
    :param int path: Unix socket path. Either this one or host and port are required.
    :param int timeout: (optional) Socket timeout.
    :param str pack_encoding: (optional) Character encoding used to pack data
        using Messagepack.
    :param str unpack_encoding: (optional) Character encoding used to unpack
        data using Messagepack.
    :param dict pack_params: (optional) Parameters to pass to Messagepack Packer
    :param dict unpack_params: (optional) Parameters to pass to Messagepack
        Unpacker.
    """
    def __init__(self,
                 host=None,
                 port=None,
                 path=None,
                 timeout=3,
                 loop=None,
                 pack_encoding='utf-8',
                 unpack_encoding='utf-8',
                 pack_params=None,
                 unpack_params=None):
        self._host = host
        self._port = port
        self._path = path
        self._timeout = timeout

        self._loop = loop
        self._conn = None
        self._msg_id = 0
        self._pack_encoding = pack_encoding
        self._pack_params = pack_params or dict()
        self._unpack_encoding = unpack_encoding
        self._unpack_params = unpack_params or dict(use_list=False)

    def getpeername(self):
        """Return the address of the remote endpoint."""
        return (self._host, self._port) if self._host else ('unix', self._path)

    def close(self):
        try:
            self._conn.close()
        except AttributeError:
            pass

    async def _open_connection(self):
        _logger.debug("connect to %s:%s...", *self.getpeername())
        if self._host:
            reader, writer = await asyncio.open_connection(self._host,
                                                           self._port,
                                                           loop=self._loop)
        else:
            reader, writer = await asyncio.open_unix_connection(
                self._path, loop=self._loop)
        self._conn = Connection(
            reader, writer,
            msgpack.Unpacker(encoding=self._unpack_encoding,
                             **self._unpack_params))
        _logger.debug("Connection to %s:%s established", *self.getpeername())

    async def call(self, method, *args, _close=False):
        """Calls a RPC method.

        :param str method: Method name.
        :param args: Method arguments.
        :param _close: Close the connection at the end of the request. Defaults to false
        """

        _logger.debug('creating request')
        req = self._create_request(method, args)

        if self._conn is None or self._conn.is_closed():
            await self._open_connection()

        try:
            _logger.debug('Sending req: %s', req)
            await self._conn.sendall(req, self._timeout)
            _logger.debug('Sending complete')
        except asyncio.TimeoutError as te:
            _logger.error("Write request to %s:%s timeout",
                          *self.getpeername())
            raise te
        except Exception as e:
            raise e

        response = None
        try:
            _logger.debug('receiving result from server')
            response = await self._conn.recvall(self._timeout)
            _logger.debug('receiving result completed')
        except asyncio.TimeoutError as te:
            _logger.error("Read request to %s:%s timeout", *self.getpeername())
            self._conn.reader.set_exception(te)
            raise te
        except Exception as e:
            self._conn.reader.set_exception(e)
            raise e

        if response is None:
            raise IOError("Connection closed")

        if not isinstance(response, tuple):
            logging.debug('Protocol error, received unexpected data: %r',
                          response)
            raise RPCProtocolError('Invalid protocol')

        if _close:
            self.close()

        return self._parse_response(response)

    async def call_once(self, method, *args):
        """Call an RPC Method, then close the connection

        :param str method: Method name.
        :param args: Method arguments.
        :param _close: Close the connection at the end of the request. Defaults to false
        """
        return await self.call(method, *args, _close=True)

    def _create_request(self, method, args):
        self._msg_id += 1

        req = (MSGPACKRPC_REQUEST, self._msg_id, method, args)

        return msgpack.packb(req,
                             encoding=self._pack_encoding,
                             **self._pack_params)

    def _parse_response(self, response):
        if (len(response) != 4 or response[0] != MSGPACKRPC_RESPONSE):
            raise RPCProtocolError('Invalid protocol')

        (_, msg_id, error, result) = response

        if msg_id != self._msg_id:
            raise RPCError('Invalid Message ID')

        if error and len(error) == 2:
            if error[0] == 'MethodNotFoundError':
                raise MethodNotFoundError(error[1])
            raise EnhancedRPCError(*error)
        elif error:
            raise RPCError(error)

        return result

    async def __aenter__(self):
        await self._open_connection()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if self._conn and not self._conn.is_closed():
            logging.debug('Closing connection from context manager')
            self.close()
コード例 #7
0
ファイル: server.py プロジェクト: dmig/aiorpc
async def serve(reader, writer):
    """Serve function.
    Don't use this outside asyncio.start_server.
    """
    global _unpack_encoding, _unpack_params
    _logger.debug('enter serve: %s', writer.get_extra_info('peername'))

    conn = Connection(
        reader, writer,
        msgpack.Unpacker(encoding=_unpack_encoding, **_unpack_params))

    while not conn.is_closed():
        req = None
        try:
            req = await conn.recvall(_timeout)
        except asyncio.TimeoutError:
            await asyncio.sleep(3)
            _logger.warning(
                "Client did not send any data before timeout. Closing connection..."
            )
            conn.close()
            continue
        except IOError:
            break
        except Exception as e:
            conn.reader.set_exception(e)
            raise e

        if not isinstance(req, (tuple, list)):
            try:
                await _send_error(conn, "Invalid protocol", -1, None)
                # skip the rest of iteration code after sending error
                continue

            except Exception as e:
                _logger.error("Error when receiving req: %s", e)

        req_start = time.time()
        method = None
        msg_id = None
        args = None
        try:
            _logger.debug('parsing req: %s', req)
            msg_id, method, args, method_name = _parse_request(req)
            _logger.debug('parsing completed: %s', req)
        except Exception as e:
            _logger.exception("Exception raised in _parse_request(%s)", req)

            # skip the rest of iteration code since we already got an error
            continue

        # Execute the parsed request
        try:
            if not method:
                raise MethodNotFoundError(method_name)

            _logger.debug('calling method: %s', method)
            ret = method.__call__(*args)
            if asyncio.iscoroutine(ret):
                _logger.debug("start to wait_for")
                ret = await asyncio.wait_for(ret, _timeout)
            _logger.debug('calling %s completed. result: %s', method, ret)
        except Exception as e:
            _logger.exception("Caught Exception in `%s`", method_name)
            await _send_error(conn, type(e).__name__, str(e), msg_id)
            _logger.debug('sending exception %s completed', e)
        else:
            _logger.debug('sending result: %s', ret)
            await _send_result(conn, ret, msg_id)
            _logger.debug('sending result %s completed', ret)

        req_end = time.time()
        _logger.info("Method `%s` took %fms", method_name,
                     (req_end - req_start) * 1000)