Example #1
0
def test_batch_response():
    response = BatchResponse(
        {SuccessResponse("foo", id=1), SuccessResponse("bar", id=2)}
    )
    expected = [
        {"jsonrpc": "2.0", "result": "foo", "id": 1},
        {"jsonrpc": "2.0", "result": "bar", "id": 2},
    ]
    assert response.wanted == True
    for r in response.deserialized():
        assert r in expected
Example #2
0
async def server_handle(websocket, path):
    request = await websocket.recv()

    json_request = json.loads(request)
    if isinstance(json_request, list):
        if any(i["method"] == "test_cancel" for i in json_request):
            got_cancel.set_result(True)
            response = BatchResponse()
            for i in json_request:
                response.append(RequestResponse(i["id"], ["CANCELLED"]))
        elif any(i["method"] == "test_progress" for i in json_request):
            response = BatchResponse()
            for i in json_request:
                progress_notification = rockets.Request(
                    "progress",
                    {"amount": 0.5, "operation": "almost done", "id": i["id"]},
                )
                await websocket.send(progress_notification.json)
                response.append(RequestResponse(i["id"], "DONE"))
        else:
            response = await methods.dispatch(request)
    else:
        response = await methods.dispatch(request)
    if not response.is_notification:
        await websocket.send(str(response))
Example #3
0
async def server_handle(websocket, path):
    request = await websocket.recv()

    json_request = json.loads(request)
    if isinstance(json_request, list):
        if any(i['method'] == 'test_cancel' for i in json_request):
            got_cancel.set_result(True)
            response = BatchResponse()
            for i in json_request:
                response.append(RequestResponse(i['id'], ['CANCELLED']))
        elif any(i['method'] == 'test_progress' for i in json_request):
            response = BatchResponse()
            for i in json_request:
                progress_notification = rockets.Request(
                    'progress', {
                        'amount': 0.5,
                        'operation': 'almost done',
                        'id': i['id']
                    })
                await websocket.send(progress_notification.json)
                response.append(RequestResponse(i['id'], 'DONE'))
        else:
            response = await methods.dispatch(request)
    else:
        response = await methods.dispatch(request)
    if not response.is_notification:
        await websocket.send(str(response))
async def call_requests(requests: Union[Request,
                                        Iterable[Request]], methods: Methods,
                        caller: Caller, debug: bool) -> Response:
    if isinstance(requests, collections.Iterable):
        responses = (safe_call(r, methods, caller=caller, debug=debug)
                     for r in requests)
        return BatchResponse(await asyncio.gather(*responses))
    return await safe_call(requests, methods, caller=caller, debug=debug)
Example #5
0
    async def dispatch(self, methods, context=None):
        """
        Process a JSON-RPC request.

        Calls the requested method(s), and returns the result.

        :param methods: Collection of methods to dispatch to. Can be a ``list``
            of functions, a ``dict`` of name:method pairs, or a ``Methods``
            object.
        :param context: Optional context object which will be passed through to
            the RPC methods.
        """
        # Init may have failed to parse the request, in which case the response
        # would already be set
        if not self.response:
            # Batch request
            if isinstance(self.requests, list):
                # First convert each to a Request object
                requests = [
                    self.request_type(r, context=context)
                    for r in self.requests
                ]
                # Call each request
                response = await asyncio.gather(
                    *[r.call(methods) for r in requests])
                for request in self.requests:
                    self.futures.extend(request.futures)
                # Remove notification responses (as per spec)
                response = [r for r in response if not r.is_notification]
                # If the response list is empty, return nothing
                self.response = BatchResponse(
                    response) if response else NotificationResponse()
            # Single request
            else:
                # Convert to a Request object
                request = self.request_type(self.requests,
                                            self.websocket,
                                            context=context)
                # Call the request
                self.response = await request.call(methods)
                self.futures.extend(request.futures)
        assert self.response, 'Response must be set'
        assert self.response.http_status, 'Must have http_status set'
        if config.log_responses:
            self.log_response(self.response)
        return self.response
Example #6
0
 def test(self):  # pylint: disable=no-self-use
     str(BatchResponse())
Example #7
0
 def test(self):
     str(BatchResponse())
Example #8
0
def dispatch(methods, request):
    """Dispatch JSON-RPC requests to a collection of methods::

        r = dispatch([cat, dog], {'jsonrpc': '2.0', 'method': 'cat', 'id': 1})

    The first parameter can be either:

    - A *list* of methods, or
    - A *dictionary* of name:method pairs.

    When using a **list**, the methods must be identifiable by a ``__name__``
    attribute.

    Functions already have a ``__name__`` attribute::

        >>> def cat():
        ...     return 'meow'
        ...
        >>> cat.__name__
        'cat'
        >>> dispatch([cat], ...)

    Lambdas require setting it::

        >>> cat = lambda: 'meow'
        >>> cat.__name__ = 'cat'
        >>> dispatch([cat], ...)

    As do partials::

        >>> max_ten = partial(min, 10)
        >>> max_ten.__name__ = 'max_ten'
        >>> dispatch([max_ten], ...)

    Alternatively, use a **dictionary**::

        >>> dispatch({'cat': cat, 'max_ten': max_ten}, ...)

    The :mod:`methods` module also gives nice and easy ways to build the
    collection of methods.

    :param methods:
        Collection of methods to dispatch to.
    :param request:
        JSON-RPC request - can be a JSON-serializable object, or a string.
        Strings must be valid json (use double quotes!).
    :returns:
        A :mod:`response` object.
    """
    # Process the request
    response = None
    try:
        # Log the request
        request_log.info(request)
        # If the request is a string, convert it to a dict first
        if isinstance(request, string_types):
            request = _string_to_dict(request)
        # Batch requests
        if isinstance(request, list):
            # An empty list is invalid
            if len(request) == 0:
                raise InvalidRequest()
            # Process each request
            response = BatchResponse()
            for r in request:
                try:
                    req = Request(r)
                except InvalidRequest as e:
                    resp = ExceptionResponse(e, None)
                else:
                    resp = req.process(methods)
                response.append(resp)
            # Remove Notification responses
            response = BatchResponse([
                r for r in response if not isinstance(r, NotificationResponse)
            ])
            # "Nothing is returned for all notification batches"
            if not response:
                response = NotificationResponse()  # pylint: disable=redefined-variable-type
        # Single request
        else:
            response = Request(request).process(methods)
    except JsonRpcServerError as e:
        response = ExceptionResponse(e, None)
    # Batch requests can have mixed results, just return 200
    http_status = 200 if isinstance(request, list) else response.http_status
    # Log the response
    response_log.info(str(response),
                      extra={
                          'http_code': http_status,
                          'http_reason': HTTP_STATUS_CODES[http_status]
                      })
    return response
Example #9
0
def dispatch(methods, request):
    """Dispatch JSON-RPC requests to a collection of methods::

        r = dispatch([cat, dog], {'jsonrpc': '2.0', 'method': 'cat', 'id': 1})

    The first parameter can be either:

    - A *list* of methods, or
    - A *dictionary* of name:method pairs.

    When using a **list**, the methods must be identifiable by a ``__name__``
    attribute.

    Functions already have a ``__name__`` attribute::

        >>> def cat():
        ...     return 'meow'
        ...
        >>> cat.__name__
        'cat'
        >>> dispatch([cat], ...)

    Lambdas require setting it::

        >>> cat = lambda: 'meow'
        >>> cat.__name__ = 'cat'
        >>> dispatch([cat], ...)

    As do partials::

        >>> max_ten = partial(min, 10)
        >>> max_ten.__name__ = 'max_ten'
        >>> dispatch([max_ten], ...)

    Alternatively, use a **dictionary**::

        >>> dispatch({'cat': cat, 'max_ten': max_ten}, ...)

    The :mod:`methods` module also gives nice and easy ways to build the
    collection of methods.

    :param methods:
        Collection of methods to dispatch to.
    :param request:
        JSON-RPC request - can be a JSON-serializable object, or a string.
        Strings must be valid json (use double quotes!).
    :returns:
        A :mod:`response` object.
    """
    # Process the request
    response = None
    try:
        # Log the request
        request_log.info(request)
        # If the request is a string, convert it to a dict first
        if isinstance(request, string_types):
            request = _string_to_dict(request)
        # Batch requests
        if isinstance(request, list):
            # An empty list is invalid
            if len(request) == 0:
                raise InvalidRequest()
            # Process each request
            response = BatchResponse()
            for r in request:
                try:
                    req = Request(r)
                except InvalidRequest as e:
                    resp = ExceptionResponse(e, None)
                else:
                    resp = req.process(methods)
                response.append(resp)
            # Remove Notification responses
            response = BatchResponse(
                [r for r in response if not isinstance(
                    r, NotificationResponse)])
            # "Nothing is returned for all notification batches"
            if not response:
                response = NotificationResponse() # pylint: disable=redefined-variable-type
        # Single request
        else:
            response = Request(request).process(methods)
    except JsonRpcServerError as e:
        response = ExceptionResponse(e, None)
    # Batch requests can have mixed results, just return 200
    http_status = 200 if isinstance(request, list) else response.http_status
    # Log the response
    response_log.info(str(response), extra={
        'http_code': http_status,
        'http_reason': HTTP_STATUS_CODES[http_status]})
    return response