예제 #1
0
    async def dispatch(request, channel_name=None):
        req_json = request.json
        url = request.url
        channel = channel_name if channel_name is not None \
            else StubCollection().conf[ConfigKey.CHANNEL]

        context = {
            "url": url,
            "channel": channel,
        }

        try:
            client_ip = request.remote_addr if request.remote_addr else request.ip
            Logger.info(f'rest_server_v3d request with {req_json}',
                        DISPATCH_V3D_TAG)
            Logger.info(f"{client_ip} requested {req_json} on {url}")

            validate_jsonschema_v3(request=req_json)
        except GenericJsonRpcServerError as e:
            response = ExceptionResponse(e, request_id=req_json.get('id', 0))
        except Exception as e:
            response = ExceptionResponse(e, request_id=req_json.get('id', 0))
        else:
            response = await methods.dispatch(req_json, context=context)
        Logger.info(f'rest_server_v3d with response {response}',
                    DISPATCH_V3D_TAG)
        return sanic_response.json(response,
                                   status=response.http_status,
                                   dumps=json.dumps)
예제 #2
0
    async def dispatch(request, channel_name=None):
        req_json = request.json
        url = request.url
        channel = channel_name if channel_name else StubCollection().conf[
            ConfigKey.CHANNEL]
        req_json['method'] = convert_upper_camel_method_to_lower_camel(
            req_json['method'])

        if 'params' in req_json and 'message' in req_json[
                'params']:  # this will be removed after update.
            req_json['params'] = req_json['params']['message']

        context = {'url': url, 'channel': channel}

        try:
            client_ip = request.remote_addr if request.remote_addr else request.ip
            Logger.info(f'rest_server_node request with {req_json}',
                        DISPATCH_NODE_TAG)
            Logger.info(f'{client_ip} requested {req_json} on {url}')

            validate_jsonschema_node(request=req_json)
        except GenericJsonRpcServerError as e:
            response = ExceptionResponse(e, request_id=req_json.get('id', 0))
        except Exception as e:
            response = ExceptionResponse(e, request_id=req_json.get('id', 0))
        else:
            response = await methods.dispatch(req_json, context=context)
        Logger.info(f'rest_server_node with response {response}',
                    DISPATCH_NODE_TAG)
        return sanic_response.json(response,
                                   status=response.http_status,
                                   dumps=json.dumps)
예제 #3
0
    async def dispatch(request: 'SanicRequest'):
        req = request.json
        url = request.url

        context = {"url": url}

        response: Union[Response, DictResponse, BatchResponse]
        try:
            client_ip = request.remote_addr if request.remote_addr else request.ip
            Logger.info(f'rest_server_v2 request with {req}', DISPATCH_V2_TAG)
            Logger.info(f"{client_ip} requested {req} on {url}")

            validate_jsonschema_v2(request=req)
        except GenericJsonRpcServerError as e:
            Logger.debug(f'dispatch() validate exception = {e}')
            response = ExceptionResponse(e, id=req.get('id', 0), debug=False)
        else:
            response = await async_dispatch(request.body,
                                            methods,
                                            context=context)

        Logger.info(f'rest_server_v2 response with {response}',
                    DISPATCH_V2_TAG)
        return sanic_response.json(response.deserialized(),
                                   status=response.http_status,
                                   dumps=json.dumps)
예제 #4
0
    async def dispatch(request: 'SanicRequest', channel_name: str = ""):
        req_json = request.json
        url = request.url
        channel = channel_name if channel_name else StubCollection().conf[ConfigKey.CHANNEL]

        context = {
            "url": url,
            "channel": channel,
        }

        response: Union[Response, DictResponse, BatchResponse]
        try:
            client_ip = request.remote_addr if request.remote_addr else request.ip
            Logger.info(f'rest_server_v3d request with {req_json}', DISPATCH_V3D_TAG)
            Logger.info(f"{client_ip} requested {req_json} on {url}")

            validate_jsonschema_v3(request=req_json)
        except GenericJsonRpcServerError as e:
            response = ApiErrorResponse(id=req_json.get('id', 0),
                                        code=e.code,
                                        message=str(e),
                                        http_status=e.http_status,
                                        debug=False)
        except Exception as e:
            response = ExceptionResponse(e, id=req_json.get('id', 0), debug=False)
        else:
            response = await async_dispatch(request.body, methods, context=context)
        Logger.info(f'rest_server_v3d with response {response}', DISPATCH_V3D_TAG)
        return sanic_response.json(response.deserialized(), status=response.http_status, dumps=json.dumps)
예제 #5
0
    async def dispatch(request: 'SanicRequest', channel_name: str = ""):
        """Node dispatch

        FIXME : this dispatch is not considered to support batch request.
            If you want to support batch request, need to update code that using req_json.
        """

        req_json = request.json
        url = request.url
        channel = channel_name if channel_name else StubCollection().conf[
            ConfigKey.CHANNEL]
        req_json['method'] = convert_upper_camel_method_to_lower_camel(
            req_json['method'])

        if 'params' in req_json and 'message' in req_json[
                'params']:  # this will be removed after update.
            req_json['params'] = req_json['params']['message']

        context = {'url': url, 'channel': channel}

        response: Union[Response, DictResponse, BatchResponse]
        try:
            client_ip = request.remote_addr if request.remote_addr else request.ip
            Logger.info(f'rest_server_node request with {req_json}',
                        DISPATCH_NODE_TAG)
            Logger.info(f'{client_ip} requested {req_json} on {url}')

            validate_jsonschema_node(request=req_json)
        except GenericJsonRpcServerError as e:
            response = ExceptionResponse(e,
                                         id=req_json.get('id', 0),
                                         debug=False)
        except Exception as e:
            response = ExceptionResponse(e,
                                         id=req_json.get('id', 0),
                                         debug=False)
        else:
            response = await async_dispatch(request.body,
                                            methods,
                                            context=context)

        Logger.info(f'rest_server_node with response {response}',
                    DISPATCH_NODE_TAG)
        return sanic_response.json(response.deserialized(),
                                   status=response.http_status,
                                   dumps=json.dumps)
예제 #6
0
 def test_jsonrpcservererror(self):
     response = ExceptionResponse(InvalidParams(), None)
     self.assertEqual(
         {
             'jsonrpc': '2.0',
             'error': {
                 'code': -32602,
                 'message': 'Invalid params'
             },
             'id': None
         }, response)
예제 #7
0
 def test_non_jsonrpcservererror(self):
     response = ExceptionResponse(ValueError(), None)
     self.assertEqual(
         {
             'jsonrpc': '2.0',
             'error': {
                 'code': -32000,
                 'message': 'Server error'
             },
             'id': None
         }, response)
예제 #8
0
 def test_with_id(self):
     response = ExceptionResponse(InvalidParams(), 1)
     self.assertEqual(
         {
             'jsonrpc': '2.0',
             'error': {
                 'code': -32602,
                 'message': 'Invalid params'
             },
             'id': 1
         }, response)
예제 #9
0
 def test_jsonrpcservererror(self):
     response = ExceptionResponse(InvalidParams(), None)
     self.assertEqual(
         {
             "jsonrpc": "2.0",
             "error": {
                 "code": -32602,
                 "message": "Invalid params"
             },
             "id": None,
         },
         response,
     )
예제 #10
0
 def test_non_jsonrpcservererror(self):
     response = ExceptionResponse(ValueError(), None)
     self.assertEqual(
         {
             "jsonrpc": "2.0",
             "error": {
                 "code": -32000,
                 "message": "Server error"
             },
             "id": None,
         },
         response,
     )
예제 #11
0
 def test_with_id(self):
     response = ExceptionResponse(InvalidParams(), 1)
     self.assertEqual(
         {
             "jsonrpc": "2.0",
             "error": {
                 "code": -32602,
                 "message": "Invalid params"
             },
             "id": 1,
         },
         response,
     )
예제 #12
0
 def test_with_data(self):
     config.debug = True
     response = ExceptionResponse(InvalidParams('Password missing'), 1)
     self.assertEqual(
         {
             'jsonrpc': '2.0',
             'error': {
                 'code': -32602,
                 'message': 'Invalid params',
                 'data': 'Password missing'
             },
             'id': 1
         }, response)
예제 #13
0
    async def dispatch(request, channel_name=None):
        req_json = request.json
        url = request.url
        # channel = channel_name if channel_name is not None \
        #     else StubCollection().conf[ConfigKey.CHANNEL]

        context = {
            "url": url,
            "channel": 'icon_dex',
        }

        try:
            client_ip = request.remote_addr if request.remote_addr else request.ip
            Logger.info(f'rest_server_v3 request with {req_json}',
                        DISPATCH_V3_TAG)
            Logger.info(f"{client_ip} requested {req_json} on {url}")

            validate_jsonschema_v3(request=req_json)
        except GenericJsonRpcServerError as e:
            response = ExceptionResponse(e,
                                         id=req_json.get('id', 0),
                                         debug=False)
        except Exception as e:
            response = ExceptionResponse(e,
                                         id=req_json.get('id', 0),
                                         debug=False)
        else:
            if "params" in req_json:
                req_json["params"]["context"] = context
            else:
                req_json["params"] = {"context": context}
            response: DictResponse = await async_dispatch(
                json.dumps(req_json), methods)
        Logger.info(f'rest_server_v3 with response {response}',
                    DISPATCH_V3_TAG)
        return sanic_response.json(response.deserialized(),
                                   status=response.http_status,
                                   dumps=json.dumps)
예제 #14
0
 def test_with_data(self):
     response = ExceptionResponse(InvalidParams("Password missing"),
                                  1,
                                  debug=True)
     self.assertEqual(
         {
             "jsonrpc": "2.0",
             "error": {
                 "code": -32602,
                 "message": "Invalid params",
                 "data": "Password missing",
             },
             "id": 1,
         },
         response,
     )
예제 #15
0
def dispatch(request_raw: str) -> JsonRpcResponse:
    """Dispatch a request (or requests) to methods.

    This is the main public method, it's the only one with optional params, and the only
    one that can be configured with a config file/env vars.

    Args:
        request_raw: The incoming request string.

    Returns:
        A Response.
    """
    methods = global_methods
    try:
        request_json: JSON = json.loads(request_raw)
        validator.validate(request_json)
    except JSONDecodeError as exc:
        return InvalidJSONResponse(data=str(exc), debug=True)
    except ValidationError:
        return InvalidJSONRPCResponse(data=None)

    request = create_requests(request_json, convert_camel_case=False)
    assert isinstance(request, Request)

    try:
        method_name = request.method
        method = methods.items[method_name]

        with sentry_sdk.start_span(op="rpc", transaction="rpc." + method_name) as span:
            span.set_data("args", request.args)
            span.set_data("kwargs", request.kwargs)
            result = call(method, *request.args, **request.kwargs)

        return SuccessResponse(result=result, id=request.id)

    except Exception as exc:
        traceback.print_exc()
        sys.stdout.flush()
        sys.stderr.flush()
        return ExceptionResponse(exc, id=request.id, debug=True)
예제 #16
0
 def process(self, methods):
     """Calls the method and returns a Response object."""
     error = None
     try:
         result = _call(methods, self.method_name, self.args, self.kwargs)
     # Catch any JsonRpcServerError raised (Invalid Request, etc)
     except JsonRpcServerError as e:
         error = e
     # Catch uncaught exceptions and respond with ServerError
     except Exception as e:  # pylint: disable=broad-except
         # Log the uncaught exception
         logger.exception(e)
         error = e  # pylint: disable=redefined-variable-type
     if error:
         if self.is_notification and not self.notification_errors:
             return NotificationResponse()
         else:
             return ExceptionResponse(error, self.request_id)
     # Success
     if self.is_notification:
         return NotificationResponse()
     else:
         return RequestResponse(self.request_id, result)
예제 #17
0
    async def dispatch(request):
        req = request.json
        url = request.url

        context = {"url": url}

        if "node_" in req["method"]:
            return sanic_response.text("no support method!")

        try:
            client_ip = request.remote_addr if request.remote_addr else request.ip
            Logger.info(f'rest_server_v2 request with {req}', DISPATCH_V2_TAG)
            Logger.info(f"{client_ip} requested {req} on {url}")

            validate_jsonschema_v2(request=req)
        except exception.GenericJsonRpcServerError as e:
            response = ExceptionResponse(e, request_id=req.get('id', 0))
        else:
            response = await methods.dispatch(req, context=context)
        Logger.info(f'rest_server_v2 response with {response}',
                    DISPATCH_V2_TAG)
        return sanic_response.json(response,
                                   status=response.http_status,
                                   dumps=json.dumps)
예제 #18
0
def test_exception_response_debug_enabled():
    response = ExceptionResponse(ValueError("There was an error"), id=1, debug=True)
    assert (
        str(response)
        == '{"jsonrpc": "2.0", "error": {"code": -32000, "message": "Server error", "data": "ValueError: There was an error"}, "id": 1}'
    )
예제 #19
0
def test_exception_response_with_id():
    assert (
        str(ExceptionResponse(ValueError("foo"), id=1, debug=True))
        == '{"jsonrpc": "2.0", "error": {"code": -32000, "message": "Server error", "data": "ValueError: foo"}, "id": 1}'
    )
예제 #20
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