示例#1
0
def test_compount_objects():
    """
    Test serialization for compound object types.
    """
    dataset = (
        {
            'asdf':
            b'\x01\x23\x45\x67',
            'qwer':
            1234.5678,
            'zxcv': [
                float('inf'),
                float('-inf'),
                0.,
                0.0000000000000000000001,
                {
                    'i': 3,
                    'j': 4,
                },
            ],
        },
        None,
        [
            True,
            {
                'key1': False,
                'key2': [2.71828],
            },
        ],
    )

    for data in dataset:
        assert data == deserialize(serialize(data))
示例#2
0
def test_containers():
    """
    Test serialization for container types:
        - list
        - dict
    """
    dataset = (
        [
            None, True, False, 1000, 3.14,
            float('inf'),
            float('-inf'), 'asdf', b'qwerzxcv\x0f'
        ],
        {
            'a': None,
            'b': True,
            'c': False,
            'd': 1000,
            'e': 3.14,
            'f': float('inf'),
            'g': float('-inf'),
            'h': b'qwerzxcv\x0f',
            'i': 'asdf',
        },
    )

    for data in dataset:
        assert data == deserialize(serialize(data))
示例#3
0
    def call(self, server, method, args=(), kwargs={}, timeout=None):
        """
        Call an RPC method of a server with args and kwargs.
        If `timeout` is None, blocks indefinitely.
        If `timeout` is a number, blocks `timeout` seconds and raises
        RPCTimeoutError on timeout.
        """
        if timeout is None or timeout < 0:
            timeout = float('inf')

        sockets = self._sockets
        if server not in sockets:
            self.__connect(server)
        socket = sockets[server]

        request_id = str(uuid.uuid4())
        request = serialize([request_id, method, args, kwargs])

        start_time = time.monotonic()
        events = {}

        current_time = start_time
        elapsed_time = current_time - start_time

        retry_timeout = self._retry_timeout
        while elapsed_time <= timeout:
            socket.send(request)
            timeout_ms = 1000 * max(0, min(retry_timeout, timeout - elapsed_time))
            logger.debug('Polling sockets with %s ms timeout', timeout_ms)
            events = dict(self._poller.poll(timeout=timeout_ms))

            if socket in events:
                break

            logger.error('No response from "%s" - reconnecting...' % server)
            self.__disconnect(server)
            self.__connect(server)
            socket = sockets[server]

            current_time = time.monotonic()
            elapsed_time = current_time - start_time

        if socket not in events:
            raise RPCTimeoutError('Service "%s" not responding' % server)

        response_data = socket.recv()
        response = deserialize(response_data)
        [response_id, payload, is_exception] = response

        if request_id != response_id:
            raise RPCError('Internal error (request ID does not match)')

        if is_exception:
            raise RPCError(payload)

        return payload
示例#4
0
 async def _multipoll(self):
     logger.debug('Multipoll started.')
     try:
         while True:
             for socket, _ in await self.poller.poll():
                 null, response_data = await socket.recv_multipart()
                 [response_id, payload,
                  is_exception] = deserialize(response_data)
                 self.response_map[response_id].put_nowait(response_data)
     except asyncio.CancelledError:
         logger.debug('Multipoll stopped.')
示例#5
0
    async def __handle_request(self, socket: zmq.Socket, data: bytes):
        token, null, request_data = data

        try:
            request = deserialize(request_data)
            [request_id, method_name, args, kwargs] = request

        except (SerializationError, ValueError) as exc:
            self.__logger.error('Received malformed RPC request!')
            response_data = str(exc)
            is_exception = True

        else:
            if request_id in self.__cache:
                self.__logger.debug('Returning request from cache')
                token, null, response_data = await self.__cache[request_id]

            else:
                self.__cache[request_id] = asyncio.Future()

                try:
                    method = self._rpc_methods[method_name]
                except KeyError:
                    payload = 'Invalid RPC method name: %s' % method_name
                    is_exception = True
                    self.__logger.error(payload)
                else:
                    self.__logger.debug(
                        'Executing "%s" with args "%s" and kwargs "%s"...',
                        method_name,
                        str(args)[:50],
                        str(kwargs)[:50])
                    try:
                        payload = await method(self, *args, **kwargs)
                    except Exception as exc:
                        self.__logger.error('--- RPC METHOD EXCEPTION ---',
                                            exc_info=True)
                        payload = '%s: %s' % (type(exc).__name__, exc)
                        is_exception = True
                    else:
                        is_exception = False

                self.__logger.debug('Serializing RPC response "%s"...',
                                    str(payload)[:50])
                response = [request_id, payload, is_exception]
                response_data = serialize(response)
                self.__logger.debug('Sending RPC response "%s"...',
                                    str(response_data)[:50])

                if request_id in self.__cache:
                    self.__cache[request_id].set_result(
                        [token, null, response_data])
        await socket.send_multipart([token, null, response_data])
示例#6
0
    async def call(self, server, method, args=(), kwargs={}, timeout=None):
        """
        Call an RPC method of a server with args and kwargs.
        If `timeout` is None, blocks indefinitely.
        If `timeout` is a number, blocks `timeout` seconds and raises
        RPCTimeoutError on timeout.
        """
        if timeout is None or timeout < 0:
            timeout = float('inf')

        # Create message
        request_id = str(uuid.uuid4())
        request = serialize([request_id, method, args, kwargs])

        start_time = time.monotonic()
        elapsed_time = 0

        fail_count = 0

        while elapsed_time <= timeout:
            # Send request
            socket = self.connector.get_socket(server)
            await self.connector.send(socket, request)

            timeout_try = max(0,
                              min(self.retry_timeout,
                                  timeout - elapsed_time))
            try:
                # Wait response
                response_data = await asyncio.wait_for(
                    self.multipoller.poll_and_recv(request_id),
                    timeout=timeout_try,
                )
            except asyncio.TimeoutError:
                pass
            else:
                # Parse response
                response_id, payload, is_exception = deserialize(response_data)

                if request_id != response_id:
                    raise RPCError('Internal error (request ID does not match)')

                if is_exception:
                    raise RPCError(payload)
                
                return payload

            elapsed_time = time.monotonic() - start_time

        raise RPCTimeoutError('Service "%s" not responding' % server)
示例#7
0
    def __handle_request(self, socket):
        request_data = socket.recv()

        try:
            request = deserialize(request_data)
            [request_id, method_name, args, kwargs] = request
        except (SerializationError, ValueError) as exc:
            self.__logger.error('Received malformed RPC request!')
            # send empty message to keep REP state machine happy
            socket.send(b'')
            return

        if request_id in self.__cache:
            # resend response silently
            self.__logger.debug('Returning request from cache: %s', request_id)
            response_data = self.__cache[request_id]
            socket.send(self.__cache[request_id])
            return

        try:
            method = self._rpc_methods[method_name]
        except KeyError:
            payload = 'Invalid RPC method name: %s' % method_name
            is_exception = True
            self.__logger.error(payload)
        else:
            self.__logger.debug(
                'Executing "%s" with args "%s" and kwargs "%s"...',
                method_name,
                str(args)[:50],
                str(kwargs)[:50])
            try:
                payload = method(self, *args, **kwargs)
            except Exception as exc:
                self.__logger.error('--- RPC METHOD EXCEPTION ---',
                                    exc_info=True)
                payload = '%s: %s' % (type(exc).__name__, exc)
                is_exception = True
            else:
                is_exception = False

        self.__logger.debug('Serializing RPC response "%s"...',
                            str(payload)[:50])
        response = [request_id, payload, is_exception]
        response_data = serialize(response)
        self.__logger.debug('Sending RPC response "%s"...',
                            str(response_data)[:50])
        self.__cache[request_id] = response_data
        socket.send(response_data)
示例#8
0
def test_builtin():
    """
    Test serialization for builtin types:
        - null
        - bool
        - numeric (int/float)
        - strings (unicode/bytes)
    """
    dataset = (
        None,
        True,
        False,
        1000,
        3.14,
        float('inf'),
        float('-inf'),
        'asdf',
        b'qwerzxcv\x0f',
    )

    for data in dataset:
        assert data == deserialize(serialize(data))