예제 #1
0
def test_socket_queue_garbage(codec, threading_model):
    s1, s2 = _socketpair(threading_model)
    sq = SocketQueue(s2, codec, threading_model)
    s1.sendall(b'\xfa\xff\xff\xff\xde\xadabracadabra bobby jenkins\x05\x04')
    assert isinstance(sq.get(), FramingError)
    # All but DecodingError's are considered irrecoverable -> socket is closed.
    sq.join(timeout=1.0)
    assert sq.is_closed
예제 #2
0
 def __init__(self, socket, codec, services=None, **options):
     assert (hasattr(services, '_request_handlers')
             and hasattr(services, '_notification_handlers'))
     for key, value in options.items():
         setattr(self, key, value)
     self.definitions = Definitions(self.protocol, self.protocol_version,
                                    self.no_arguments_presentation)
     self.services = services
     self.socket_queue = SocketQueue(socket, codec, self.threading_model)
     self.dispatcher = Dispatcher(self)
예제 #3
0
 def __init__(self, socket, codec, services=None, **options):
     assert (hasattr(services, '_request_handlers') and
             hasattr(services, '_notification_handlers'))
     for key, value in options.items():
         setattr(self, key, value)
     self.definitions = Definitions(self.protocol,
                                    self.protocol_version,
                                    self.no_arguments_presentation)
     self.services = services
     self.socket_queue = SocketQueue(socket, codec, self.threading_model)
     self.dispatcher = Dispatcher(self)
예제 #4
0
class RpcBase(DefaultOptionsMixin):

    def __init__(self, socket, codec, services=None, **options):
        assert (hasattr(services, '_request_handlers') and
                hasattr(services, '_notification_handlers'))
        for key, value in options.items():
            setattr(self, key, value)
        self.definitions = Definitions(self.protocol,
                                       self.protocol_version,
                                       self.no_arguments_presentation)
        self.services = services
        self.socket_queue = SocketQueue(socket, codec, self.threading_model)
        self.dispatcher = Dispatcher(self)

    @property
    def is_closed(self):
        '''
        :property: bool -- Closed by peer node or with ``close()``
        '''
        return self.socket_queue.is_closed

    def invoke_request(self, method_name, *args, **kwargs):
        '''
        Invoke RPC Request.

        :param method_name: Name of the request method.
        :type method_name: str
        :param args: Arguments
        :param kwargs: Keyword Arguments.
        :returns: Response value(s) from peer.
        :raises: BsonRpcError

        A timeout for the request can be set by giving a special keyword
        argument ``timeout`` (float value of seconds) which can be prefixed
        by any number of underscores - if necessary - to differentiate it from
        the actual keyword arguments going to the peer node method call.

        e.g.
        ``invoke_request('testing', [], {'_timeout': 22, '__timeout: 10.0})``
        would call a request method ``testing(_timeout=22)`` on the RPC peer
        and wait for the response for 10 seconds.

        **NOTE:**
          Use either arguments or keyword arguments. Both can't
          be used in a single call.
          (Naturally the timeout argument does not count to the rule.)
        '''
        rec = re.compile(r'^_*timeout$')
        to_keys = sorted(filter(lambda x: rec.match(x), kwargs.keys()))
        if to_keys:
            timeout = kwargs[to_keys[0]]
            del kwargs[to_keys[0]]
        else:
            timeout = None

        def _send_request(msg_id):
            try:
                promise = self.dispatcher.register(msg_id)
                self.socket_queue.put(
                    self.definitions.request(
                        msg_id, method_name, args, kwargs))
                return promise
            except Exception as e:
                self.dispatcher.unregister(msg_id)
                raise e

        msg_id = six.next(self.id_generator)
        promise = _send_request(msg_id)
        try:
            result = promise.wait(timeout)
        except RuntimeError:
            self.dispatcher.unregister(msg_id)
            raise ResponseTimeout(u'Waiting response expired.')
        if isinstance(result, Exception):
            print("Failing method name: '{}'".format(method_name))
            raise result
        return result

    def invoke_notification(self, method_name, *args, **kwargs):
        '''
        Send an RPC Notification.

        :param method_name: Name of the notification method.
        :type method_name: str
        :param args: Arguments
        :param kwargs: Keyword Arguments.

        **NOTE:**
          Use either arguments or keyword arguments. Both can't
          be used simultaneously in a single call.
        '''
        self.socket_queue.put(
            self.definitions.notification(method_name, args, kwargs))

    def get_peer_proxy(self, requests=None, notifications=None, timeout=None):
        '''
        Get a RPC peer proxy object. Method calls to this object
        are delegated and executed on the connected RPC peer.

        :param requests: A list of method names which can be called and
                         will be delegated to peer node as requests.
                         Default: None -> All arbitrary attributes are
                         handled as requests to the peer.
        :type requests: list of str | None
        :param notifications: A list of method names which can be called and
                              will be delegated to peer node as notifications.
                              Default: None -> If ``requests`` is not ``None``
                              all other attributes are handled as
                              notifications.
        :type notifications: list of str | None
        :param timeout: Timeout in seconds, maximum time to wait responses
                        to each Request.
        :type timeout: float | None
        :returns: A proxy object. Attribute method calls delegated over RPC.

        ``get_peer_proxy()`` (without arguments) will return a proxy
        where all attribute method calls are turned into Requests,
        except calls via ``.n`` which are turned into Notifications.
        Example:
        ::

          proxy = rpc.get_peer_proxy()
          proxy.n.log_this('hello')          # -> Notification
          result = proxy.swap_this('Alise')  # -> Request

        But if arguments are given then the interpretation is explicit and
        ``.n``-delegator is not used:
        ::

          proxy = rpc.get_peer_proxy(['swap_this'], ['log_this'])
          proxy.log_this('hello')            # -> Notification
          result = proxy.swap_this('esilA')  # -> Request
        '''
        return PeerProxy(self, requests, notifications, timeout)

    def close(self):
        '''
        Close the connection and stop the internal dispatcher.
        '''
        # Closing the socket queue causes the dispatcher to close also.
        self.socket_queue.close()

    def join(self, timeout=None):
        '''
        Wait for the internal dispatcher to shut down.

        :param timeout: Timeout in seconds, max time to wait.
        :type timeout: float | None
        '''
        self.dispatcher.join(timeout=timeout)
예제 #5
0
class RpcBase(DefaultOptionsMixin):
    def __init__(self, socket, codec, services=None, **options):
        assert (hasattr(services, '_request_handlers')
                and hasattr(services, '_notification_handlers'))
        for key, value in options.items():
            setattr(self, key, value)
        self.definitions = Definitions(self.protocol, self.protocol_version,
                                       self.no_arguments_presentation)
        self.services = services
        self.socket_queue = SocketQueue(socket, codec, self.threading_model)
        self.dispatcher = Dispatcher(self)

    @property
    def is_closed(self):
        '''
        :property: bool -- Closed by peer node or with ``close()``
        '''
        return self.socket_queue.is_closed

    def invoke_request(self, method_name, *args, **kwargs):
        '''
        Invoke RPC Request.

        :param method_name: Name of the request method.
        :type method_name: str
        :param args: Arguments
        :param kwargs: Keyword Arguments.
        :returns: Response value(s) from peer.
        :raises: BsonRpcError

        A timeout for the request can be set by giving a special keyword
        argument ``timeout`` (float value of seconds) which can be prefixed
        by any number of underscores - if necessary - to differentiate it from
        the actual keyword arguments going to the peer node method call.

        e.g.
        ``invoke_request('testing', [], {'_timeout': 22, '__timeout: 10.0})``
        would call a request method ``testing(_timeout=22)`` on the RPC peer
        and wait for the response for 10 seconds.

        **NOTE:**
          Use either arguments or keyword arguments. Both can't
          be used in a single call.
          (Naturally the timeout argument does not count to the rule.)
        '''
        rec = re.compile(r'^_*timeout$')
        to_keys = sorted(filter(lambda x: rec.match(x), kwargs.keys()))
        if to_keys:
            timeout = kwargs[to_keys[0]]
            del kwargs[to_keys[0]]
        else:
            timeout = None
        msg_id = six.next(self.id_generator)
        try:
            with ResultScope(self.dispatcher, msg_id) as promise:
                self.socket_queue.put(
                    self.definitions.request(msg_id, method_name, args,
                                             kwargs))
                result = promise.wait(timeout)
        except RuntimeError:
            raise ResponseTimeout(u'Waiting response expired.')
        if isinstance(result, Exception):
            raise result
        return result

    def invoke_notification(self, method_name, *args, **kwargs):
        '''
        Send an RPC Notification.

        :param method_name: Name of the notification method.
        :type method_name: str
        :param args: Arguments
        :param kwargs: Keyword Arguments.

        **NOTE:**
          Use either arguments or keyword arguments. Both can't
          be used simultaneously in a single call.
        '''
        self.socket_queue.put(
            self.definitions.notification(method_name, args, kwargs))

    def get_peer_proxy(self, requests=None, notifications=None, timeout=None):
        '''
        Get a RPC peer proxy object. Method calls to this object
        are delegated and executed on the connected RPC peer.

        :param requests: A list of method names which can be called and
                         will be delegated to peer node as requests.
                         Default: None -> All arbitrary attributes are
                         handled as requests to the peer.
        :type requests: list of str | None
        :param notifications: A list of method names which can be called and
                              will be delegated to peer node as notifications.
                              Default: None -> If ``requests`` is not ``None``
                              all other attributes are handled as
                              notifications.
        :type notifications: list of str | None
        :param timeout: Timeout in seconds, maximum time to wait responses
                        to each Request.
        :type timeout: float | None
        :returns: A proxy object. Attribute method calls delegated over RPC.

        ``get_peer_proxy()`` (without arguments) will return a proxy
        where all attribute method calls are turned into Requests,
        except calls via ``.n`` which are turned into Notifications.
        Example:
        ::

          proxy = rpc.get_peer_proxy()
          proxy.n.log_this('hello')          # -> Notification
          result = proxy.swap_this('Alise')  # -> Request

        But if arguments are given then the interpretation is explicit and
        ``.n``-delegator is not used:
        ::

          proxy = rpc.get_peer_proxy(['swap_this'], ['log_this'])
          proxy.log_this('hello')            # -> Notification
          result = proxy.swap_this('esilA')  # -> Request
        '''
        return PeerProxy(self, requests, notifications, timeout)

    def close(self):
        '''
        Close the connection and stop the internal dispatcher.
        '''
        # Closing the socket queue causes the dispatcher to close also.
        self.socket_queue.close()

    def join(self, timeout=None):
        '''
        Wait for the internal dispatcher to shut down.

        :param timeout: Timeout in seconds, max time to wait.
        :type timeout: float | None
        '''
        self.dispatcher.join(timeout=timeout)
예제 #6
0
def test_socket_queue_basics(codec, threading_model):
    s1, s2 = _socketpair(threading_model)
    sq1 = SocketQueue(s1, codec, threading_model)
    sq2 = SocketQueue(s2, codec, threading_model)
    sq1.put(msg2)
    sq1.put(msg1)
    sq2.put(msg2)
    assert sq2.get() == msg2
    assert sq2.get() == msg1
    assert sq1.get() == msg2
    sq1.close()
    assert sq2.get() is None
    assert sq1.get() is None
    assert sq1.is_closed
    assert sq2.is_closed
    sq1.join()
    sq2.join()