def process_message(self, session: Session, data: MessageData) -> MessageData: """process a message Parameters ---------- session : Session session data : MessageData message Returns ------- MessageData response data (if exists). """ try: msg = validate_message(unpack_object(data)) if isinstance(msg, Request): if msg.method not in self.__methods: self.__logger.error('method %s not found', msg.method) return pack_response(msg.msgid, error='method {} not found'.format( msg.method)) return self.__methods[msg.method].process_request(session, msg) if isinstance(msg, Notification): if msg.method not in self.__methods: self.__logger.error('method %s not found', msg.method) return None self.__methods[msg.method].process_notification(session, msg) return None raise MPRPCException( ErrorInfo(ErrorCode.INVALID_MESSAGE, 'message must be a request or response')) except MPRPCException as err: self.__logger.error('%s', err) raise except Exception as err: self.__logger.error('%s', err) raise MPRPCException( ErrorInfo(ErrorCode.UNEXPECTED_ERROR, 'error in server: {}'.format(err))) from err
def unpack_object(data: MessageData) -> Any: """unpack data Parameters ---------- data : mprpc.message.MessageData data to unpack Returns ------- Any unpacked data Raises ------ mprpc.MPRPCException If msgpack package failed to unpack data. """ try: return unpackb(bytes(data)) except Exception as err: raise MPRPCException( ErrorInfo(ErrorCode.PARSE_ERROR, 'error in unpacking data', data)) from err
def pack_object(obj: Any) -> MessageData: """pack an object This function calls msgpack.packb function. Parameters ---------- obj : Any object to pack Returns ------- mprpc.message.MessageData packed bytes Raises ------ mprpc.MPRPCException If msgpack package failed to pack data. """ try: return MessageData(packb(obj)) except Exception as err: raise MPRPCException( ErrorInfo(ErrorCode.UNEXPECTED_ERROR, 'error in packing data: %s' % obj)) from err
def validate_data_list( data: Any, schemas: Optional[List[Optional[marshmallow.Schema]]] = None ) -> List[Any]: """validate a list of data This function repeately calls :py:func:`mprpc.message.validate_data` to validate a list of data, used for validation of parameters in request and notification messages. Parameters ---------- data : Any list of data to validate schemas : Optional[List[Optional[marshmallow.Schema]]], optional list of schemas, by default None to specify no validation. If a list is given, each element in the list is assumed to be None (no validation) or an object of a class inherited from marshmallow.Schema to use for validation. Returns ------- List[Any] validated data Raises ------ mprpc.MPRPCException If data is invalid. """ if schemas is None: # no validation is needed return data if not isinstance(data, list): raise MPRPCException( ErrorInfo(ErrorCode.PARSE_ERROR, 'data is not a list: %s' % data)) if len(schemas) != len(data): raise MPRPCException( ErrorInfo(ErrorCode.PARSE_ERROR, 'invalid length of data: %s' % data)) return [ validate_data(data_elem, schema) for (data_elem, schema) in zip(data, schemas) ]
def _process_message(self, err: ErrorInfo, data: MessageData): """process a message Parameters ---------- err : ErrorInfo error data : MessageData message data """ try: if err: raise MPRPCException(err) msg = validate_message(unpack_object(data)) if not isinstance(msg, Response): raise MPRPCException( ErrorInfo(ErrorCode.INVALID_MESSAGE, 'received a message which is not a response')) msgid = msg.msgid with self.__lock: if msgid not in self.__requests: self.__logger.warn( 'invalid msgid in received response: %d', msgid) future = self.__requests[msgid] del self.__requests[msgid] if msg.error: future.set_exception(ServerError(msg.error)) return future.set_result(msg.result) except MPRPCException as exc: self.__logger.error('%s', exc) with self.__lock: for future in self.__requests.values(): future.set_exception(MPRPCException(err)) self.__requests = dict() return
def _on_request_sent(self, err: ErrorInfo): """process on a request sent Parameters ---------- err : ErrorInfo error """ if not err: return self.__logger.error('%s', err) with self.__lock: for future in self.__requests.values(): future.set_exception(MPRPCException(err)) self.__requests = dict()
def _make_parse_error(message: str, data: Any): """raise an exception for a parse error Parameters ---------- message : str error message data : Any data Returns ------- MPRPCException exception object to raise """ return MPRPCException( ErrorInfo(ErrorCode.PARSE_ERROR, '%s: %s' % (message, data)))
def validate_data(data: Any, schema: Optional[marshmallow.Schema] = None) -> Any: """validate data This function validate `data` with `schema` using `schema.load` function, and returns the result. Parameters ---------- data : Any data to validate schema : Optional[Schema], optional schema of data, by default None to specify no validation. If an object other than None is provided, it is assumed to be an object of a class inherited from marshmallow.Schema. Returns ------- Any validated data, `data` itself or an object of user-defined types (when `@post_load` decorator is used). Raises ------ mprpc.MPRPCException If data is invalid. """ if schema is None: # no validation is needed return data try: return schema.load(data) except marshmallow.ValidationError as err: raise MPRPCException( ErrorInfo(ErrorCode.PARSE_ERROR, 'failed to parse data: %s' % data)) from err