From 0066fbea1b4e12c0739a9293353f280b7a0571d1 Mon Sep 17 00:00:00 2001 From: Gwendal Raoul Date: Thu, 30 Jul 2020 14:27:58 +0200 Subject: [PATCH 1/2] Gateway Wrapper: enhance class hierarchy Also add a metho to parse from protobuf message instead of payload and generate generic_message instead of payload directly. It is needed change for upcoming generic collection. --- .../wirepas_messaging/gateway/api/event.py | 12 ++--- .../gateway/api/generic_message.py | 51 +++++++++++++++++++ .../gateway/api/get_configs.py | 27 +++------- .../gateway/api/get_gw_info.py | 32 +++--------- .../gateway/api/get_scratchpad_status.py | 31 +++-------- .../gateway/api/process_scratchpad.py | 31 +++-------- .../gateway/api/received_data.py | 14 ++--- .../wirepas_messaging/gateway/api/request.py | 12 ++--- .../wirepas_messaging/gateway/api/response.py | 12 ++--- .../gateway/api/send_data.py | 28 +++------- .../gateway/api/set_config.py | 27 +++------- .../wirepas_messaging/gateway/api/status.py | 15 ++---- .../gateway/api/upload_scratchpad.py | 31 +++-------- 13 files changed, 108 insertions(+), 215 deletions(-) create mode 100644 wrappers/python/wirepas_messaging/gateway/api/generic_message.py diff --git a/wrappers/python/wirepas_messaging/gateway/api/event.py b/wrappers/python/wirepas_messaging/gateway/api/event.py index 3c1aaaa..5a6afc3 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/event.py +++ b/wrappers/python/wirepas_messaging/gateway/api/event.py @@ -9,8 +9,10 @@ import random import wirepas_messaging +from .generic_message import GenericMessage -class Event(object): + +class Event(GenericMessage): """ Event @@ -30,14 +32,6 @@ def __init__(self, gw_id, sink_id=None, event_id=None, **kwargs): event_id = random.getrandbits(64) self.event_id = event_id - def __str__(self): - return str(self.__dict__) - - @property - def payload(self): - """ Implement how to serialize child Event classes """ - raise NotImplementedError() - def _make_event_header(self): """ Creates the generic messaging header """ header = wirepas_messaging.gateway.EventHeader() diff --git a/wrappers/python/wirepas_messaging/gateway/api/generic_message.py b/wrappers/python/wirepas_messaging/gateway/api/generic_message.py new file mode 100644 index 0000000..a4c19e3 --- /dev/null +++ b/wrappers/python/wirepas_messaging/gateway/api/generic_message.py @@ -0,0 +1,51 @@ +""" + Generic message + ======== + + .. Copyright: + Copyright 2020 Wirepas Ltd under Apache License, Version 2.0. + See file LICENSE for full license details. +""" + +import wirepas_messaging + +from .wirepas_exceptions import GatewayAPIParsingException + + +class GenericMessage(object): + """ + Generic message + + Base class for all Events, Requests, Response + + """ + + @classmethod + def from_generic_message(cls, message): + """ Implement how to parse message """ + raise NotImplementedError() + + @classmethod + def from_payload(cls, payload): + message = wirepas_messaging.gateway.GenericMessage() + try: + message.ParseFromString(payload) + except Exception: + # Any Exception is promoted to Generic API exception + raise GatewayAPIParsingException( + "Cannot parse payload for %s" % cls.__name__ + ) + + return cls.from_generic_message(message) + + @property + def generic_message(self): + """ Implement how to generate generic message""" + raise NotImplementedError() + + @property + def payload(self): + return self.generic_message.SerializeToString() + + def __str__(self): + return str(self.__dict__) diff --git a/wrappers/python/wirepas_messaging/gateway/api/get_configs.py b/wrappers/python/wirepas_messaging/gateway/api/get_configs.py index ae024e0..2e00363 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/get_configs.py +++ b/wrappers/python/wirepas_messaging/gateway/api/get_configs.py @@ -18,7 +18,6 @@ set_config_ro, set_config_rw, ) -from .wirepas_exceptions import GatewayAPIParsingException class GetConfigsRequest(Request): @@ -33,25 +32,18 @@ def __init__(self, req_id=None, **kwargs): super(GetConfigsRequest, self).__init__(req_id=req_id, **kwargs) @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException("Cannot parse GetConfigsRequest payload") - + def from_generic_message(cls, message): d = Request._parse_request_header(message.wirepas.get_configs_req.header) return cls(d["req_id"]) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() # Fill the request header get_config = message.wirepas.get_configs_req get_config.header.CopyFrom(self._make_request_header()) - return message.SerializeToString() + return message class GetConfigsResponse(Response): @@ -70,14 +62,7 @@ def __init__(self, req_id, gw_id, res, configs, **kwargs): self.configs = configs @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException("Cannot parse GetConfigsResponse payload") - + def from_generic_message(cls, message): response = message.wirepas.get_configs_resp d = Response._parse_response_header(response.header) @@ -97,7 +82,7 @@ def from_payload(cls, payload): return cls(d["req_id"], d["gw_id"], d["res"], configs) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() response = message.wirepas.get_configs_resp @@ -110,4 +95,4 @@ def payload(self): set_config_rw(conf, config) set_config_ro(conf, config) - return message.SerializeToString() + return message diff --git a/wrappers/python/wirepas_messaging/gateway/api/get_gw_info.py b/wrappers/python/wirepas_messaging/gateway/api/get_gw_info.py index 177a941..dbf5eee 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/get_gw_info.py +++ b/wrappers/python/wirepas_messaging/gateway/api/get_gw_info.py @@ -12,8 +12,6 @@ from .request import Request from .response import Response -from .wirepas_exceptions import GatewayAPIParsingException - class GetGatewayInfoRequest(Request): """ @@ -27,27 +25,18 @@ def __init__(self, req_id=None, **kwargs): super(GetGatewayInfoRequest, self).__init__(req_id=req_id, **kwargs) @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException( - "Cannot parse GetGatewayInfoRequest payload" - ) - + def from_generic_message(cls, message): d = Request._parse_request_header(message.wirepas.get_gateway_info_req.header) return cls(d["req_id"]) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() # Fill the request header get_gateway_info = message.wirepas.get_gateway_info_req get_gateway_info.header.CopyFrom(self._make_request_header()) - return message.SerializeToString() + return message class GetGatewayInfoResponse(Response): @@ -81,16 +70,7 @@ def __init__( self.implemented_api_version = implemented_api_version @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException( - "Cannot parse GetGatewayInfoResponse payload" - ) - + def from_generic_message(cls, message): response = message.wirepas.get_gateway_info_resp d = Response._parse_response_header(response.header) @@ -106,7 +86,7 @@ def from_payload(cls, payload): ) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() response = message.wirepas.get_gateway_info_resp @@ -123,4 +103,4 @@ def payload(self): if self.implemented_api_version is not None: response.info.implemented_api_version = self.implemented_api_version - return message.SerializeToString() + return message diff --git a/wrappers/python/wirepas_messaging/gateway/api/get_scratchpad_status.py b/wrappers/python/wirepas_messaging/gateway/api/get_scratchpad_status.py index 258624d..85ca0cc 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/get_scratchpad_status.py +++ b/wrappers/python/wirepas_messaging/gateway/api/get_scratchpad_status.py @@ -19,7 +19,6 @@ ScratchpadType, ) from .gateway_result_code import GatewayResultCode -from .wirepas_exceptions import GatewayAPIParsingException class GetScratchpadStatusRequest(Request): @@ -35,16 +34,7 @@ def __init__(self, sink_id, req_id=None, **kwargs): super(GetScratchpadStatusRequest, self).__init__(sink_id, req_id, **kwargs) @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException( - "Cannot parse GetScratchpadStatusRequest payload" - ) - + def from_generic_message(cls, message): req = message.wirepas.get_scratchpad_status_req d = Request._parse_request_header(req.header) @@ -52,13 +42,13 @@ def from_payload(cls, payload): return cls(d["sink_id"], d["req_id"]) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() # Fill the request header req = message.wirepas.get_scratchpad_status_req req.header.CopyFrom(self._make_request_header()) - return message.SerializeToString() + return message class GetScratchpadStatusResponse(Response): @@ -98,16 +88,7 @@ def __init__( self.firmware_area_id = firmware_area_id @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException( - "Cannot parse GetScratchpadStatusResponse payload" - ) - + def from_generic_message(cls, message): response = message.wirepas.get_scratchpad_status_resp d = Response._parse_response_header(response.header) @@ -148,7 +129,7 @@ def from_payload(cls, payload): ) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() response = message.wirepas.get_scratchpad_status_resp @@ -175,4 +156,4 @@ def payload(self): if self.firmware_area_id is not None: response.firmware_area_id = self.firmware_area_id - return message.SerializeToString() + return message diff --git a/wrappers/python/wirepas_messaging/gateway/api/process_scratchpad.py b/wrappers/python/wirepas_messaging/gateway/api/process_scratchpad.py index dd73ab8..b1d39c3 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/process_scratchpad.py +++ b/wrappers/python/wirepas_messaging/gateway/api/process_scratchpad.py @@ -11,7 +11,6 @@ from .request import Request from .response import Response -from .wirepas_exceptions import GatewayAPIParsingException class ProcessScratchpadRequest(Request): @@ -27,16 +26,7 @@ def __init__(self, sink_id, req_id=None, **kwargs): super(ProcessScratchpadRequest, self).__init__(sink_id, req_id, **kwargs) @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException( - "Cannot parse ProcessScratchpadRequest payload" - ) - + def from_generic_message(cls, message): req = message.wirepas.process_scratchpad_req d = Request._parse_request_header(req.header) @@ -44,13 +34,13 @@ def from_payload(cls, payload): return cls(d["sink_id"], d["req_id"]) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() # Fill the request header req = message.wirepas.process_scratchpad_req req.header.CopyFrom(self._make_request_header()) - return message.SerializeToString() + return message class ProcessScratchpadResponse(Response): @@ -70,16 +60,7 @@ def __init__(self, req_id, gw_id, res, sink_id, **kwargs): ) @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException( - "Cannot parse ProcessScratchpadResponse payload" - ) - + def from_generic_message(cls, message): response = message.wirepas.process_scratchpad_resp d = Response._parse_response_header(response.header) @@ -87,10 +68,10 @@ def from_payload(cls, payload): return cls(d["req_id"], d["gw_id"], d["res"], d["sink_id"]) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() response = message.wirepas.process_scratchpad_resp response.header.CopyFrom(self._make_response_header()) - return message.SerializeToString() + return message diff --git a/wrappers/python/wirepas_messaging/gateway/api/received_data.py b/wrappers/python/wirepas_messaging/gateway/api/received_data.py index 711108f..27005ac 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/received_data.py +++ b/wrappers/python/wirepas_messaging/gateway/api/received_data.py @@ -10,7 +10,6 @@ import wirepas_messaging from .event import Event -from .wirepas_exceptions import GatewayAPIParsingException class ReceivedDataEvent(Event): @@ -70,14 +69,7 @@ def __init__( self.hop_count = hop_count @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException("Cannot parse ReceivedDataEvent payload") - + def from_generic_message(cls, message): event = message.wirepas.packet_received_event d = Event._parse_event_header(event.header) @@ -118,7 +110,7 @@ def from_payload(cls, payload): ) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() # Fill the event header event = message.wirepas.packet_received_event @@ -141,4 +133,4 @@ def payload(self): if self.hop_count > 0: event.hop_count = self.hop_count - return message.SerializeToString() + return message diff --git a/wrappers/python/wirepas_messaging/gateway/api/request.py b/wrappers/python/wirepas_messaging/gateway/api/request.py index c1977c2..968cc9c 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/request.py +++ b/wrappers/python/wirepas_messaging/gateway/api/request.py @@ -10,8 +10,10 @@ import random import wirepas_messaging +from .generic_message import GenericMessage -class Request(object): + +class Request(GenericMessage): """ Request @@ -28,14 +30,6 @@ def __init__(self, sink_id=None, req_id=None, **kwargs): req_id = random.getrandbits(64) self.req_id = req_id - def __str__(self): - return str(self.__dict__) - - @property - def payload(self): - """ Implement how to serialize child Event classes """ - raise NotImplementedError() - def _make_request_header(self): """ Creates the generic messaging header """ header = wirepas_messaging.gateway.RequestHeader() diff --git a/wrappers/python/wirepas_messaging/gateway/api/response.py b/wrappers/python/wirepas_messaging/gateway/api/response.py index 26509bc..e7d791a 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/response.py +++ b/wrappers/python/wirepas_messaging/gateway/api/response.py @@ -10,8 +10,10 @@ import wirepas_messaging from .gateway_result_code import GatewayResultCode +from .generic_message import GenericMessage -class Response(object): + +class Response(GenericMessage): """ Response @@ -30,14 +32,6 @@ def __init__(self, req_id, gw_id, res, sink_id=None, **kwargs): self.req_id = req_id self.res = res - def __str__(self): - return str(self.__dict__) - - @property - def payload(self): - """ Implement how to serialize child Event classes """ - raise NotImplementedError() - def _make_response_header(self): """ Creates the generic messaging header """ header = wirepas_messaging.gateway.ResponseHeader() diff --git a/wrappers/python/wirepas_messaging/gateway/api/send_data.py b/wrappers/python/wirepas_messaging/gateway/api/send_data.py index d09eec4..fb542f9 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/send_data.py +++ b/wrappers/python/wirepas_messaging/gateway/api/send_data.py @@ -12,8 +12,6 @@ from .request import Request from .response import Response -from .wirepas_exceptions import GatewayAPIParsingException - class SendDataRequest(Request): """ @@ -57,14 +55,7 @@ def __init__( self.hop_limit = hop_limit @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException("Cannot parse SendDataRequest payload") - + def from_generic_message(cls, message): req = message.wirepas.send_packet_req d = Request._parse_request_header(req.header) @@ -101,7 +92,7 @@ def from_payload(cls, payload): ) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() # Fill the request header @@ -124,7 +115,7 @@ def payload(self): if self.hop_limit > 0: req.hop_limit = self.hop_limit - return message.SerializeToString() + return message class SendDataResponse(Response): @@ -142,14 +133,7 @@ def __init__(self, req_id, gw_id, res, sink_id, **kwargs): super(SendDataResponse, self).__init__(req_id, gw_id, res, sink_id, **kwargs) @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException("Cannot parse SendDataResponse payload") - + def from_generic_message(cls, message): response = message.wirepas.send_packet_resp d = Response._parse_response_header(response.header) @@ -157,10 +141,10 @@ def from_payload(cls, payload): return cls(d["req_id"], d["gw_id"], d["res"], d["sink_id"]) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() response = message.wirepas.send_packet_resp response.header.CopyFrom(self._make_response_header()) - return message.SerializeToString() + return message diff --git a/wrappers/python/wirepas_messaging/gateway/api/set_config.py b/wrappers/python/wirepas_messaging/gateway/api/set_config.py index 0508a7e..1cd31eb 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/set_config.py +++ b/wrappers/python/wirepas_messaging/gateway/api/set_config.py @@ -20,7 +20,6 @@ parse_config_ro, set_config_ro, ) -from .wirepas_exceptions import GatewayAPIParsingException class SetConfigRequest(Request): @@ -54,14 +53,7 @@ def __init__(self, sink_id, new_config, req_id=None, **kwargs): self.new_config = new_config @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException("Cannot parse SetConfigRequest payload") - + def from_generic_message(cls, message): req = message.wirepas.set_config_req d = Request._parse_request_header(req.header) @@ -77,7 +69,7 @@ def from_payload(cls, payload): return cls(req.config.sink_id, new_config, d["req_id"]) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() # Fill the request header set_config = message.wirepas.set_config_req @@ -87,7 +79,7 @@ def payload(self): set_config_rw(set_config.config, self.new_config) set_config_keys(set_config.config.keys, self.new_config) - return message.SerializeToString() + return message class SetConfigResponse(Response): @@ -108,14 +100,7 @@ def __init__(self, req_id, gw_id, res, sink_id, config, **kwargs): self.config = config @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException("Cannot parse SetConfigResponse payload") - + def from_generic_message(cls, message): response = message.wirepas.set_config_resp d = Response._parse_response_header(response.header) @@ -131,7 +116,7 @@ def from_payload(cls, payload): return cls(d["req_id"], d["gw_id"], d["res"], d["sink_id"], new_config) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() response = message.wirepas.set_config_resp @@ -142,4 +127,4 @@ def payload(self): set_config_rw(response.config, self.config) set_config_ro(response.config, self.config) - return message.SerializeToString() + return message diff --git a/wrappers/python/wirepas_messaging/gateway/api/status.py b/wrappers/python/wirepas_messaging/gateway/api/status.py index 78a3552..be5a6f4 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/status.py +++ b/wrappers/python/wirepas_messaging/gateway/api/status.py @@ -11,7 +11,6 @@ import wirepas_messaging from .event import Event -from .wirepas_exceptions import GatewayAPIParsingException # This API should never be changes in future (prupose of protobuf) API_VERSION = 1 @@ -49,15 +48,7 @@ def __init__(self, gw_id, state, version=API_VERSION, event_id=None, **kwargs): self.version = version @classmethod - def from_payload(cls, payload): - """ Converts a protobuff message into a python object """ - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException("Cannot parse StatusEvent payload") - + def from_generic_message(cls, message): event = message.wirepas.status_event if event.state == wirepas_messaging.gateway.ON: @@ -72,7 +63,7 @@ def from_payload(cls, payload): return cls(d["gw_id"], online, event_id=d["event_id"]) @property - def payload(self): + def generic_message(self): """ Returns a proto serialization of itself """ message = wirepas_messaging.gateway.GenericMessage() @@ -86,4 +77,4 @@ def payload(self): else: status.state = wirepas_messaging.gateway.OFF - return message.SerializeToString() + return message diff --git a/wrappers/python/wirepas_messaging/gateway/api/upload_scratchpad.py b/wrappers/python/wirepas_messaging/gateway/api/upload_scratchpad.py index bc41664..304ebbc 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/upload_scratchpad.py +++ b/wrappers/python/wirepas_messaging/gateway/api/upload_scratchpad.py @@ -11,7 +11,6 @@ from .request import Request from .response import Response -from .wirepas_exceptions import GatewayAPIParsingException class UploadScratchpadRequest(Request): @@ -30,16 +29,7 @@ def __init__(self, seq, sink_id, req_id=None, scratchpad=None, **kwargs): self.scratchpad = scratchpad @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException( - "Cannot parse UploadScratchpadRequest payload" - ) - + def from_generic_message(cls, message): req = message.wirepas.upload_scratchpad_req d = Request._parse_request_header(req.header) @@ -52,7 +42,7 @@ def from_payload(cls, payload): return cls(req.seq, d["sink_id"], d["req_id"], scratchpad) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() # Fill the request header req = message.wirepas.upload_scratchpad_req @@ -62,7 +52,7 @@ def payload(self): if self.scratchpad is not None: req.scratchpad = self.scratchpad - return message.SerializeToString() + return message class UploadScratchpadResponse(Response): @@ -82,16 +72,7 @@ def __init__(self, req_id, gw_id, res, sink_id, **kwargs): ) @classmethod - def from_payload(cls, payload): - message = wirepas_messaging.gateway.GenericMessage() - try: - message.ParseFromString(payload) - except Exception: - # Any Exception is promoted to Generic API exception - raise GatewayAPIParsingException( - "Cannot parse UploadScratchpadResponse payload" - ) - + def from_generic_message(cls, message): response = message.wirepas.upload_scratchpad_resp d = Response._parse_response_header(response.header) @@ -99,10 +80,10 @@ def from_payload(cls, payload): return cls(d["req_id"], d["gw_id"], d["res"], d["sink_id"]) @property - def payload(self): + def generic_message(self): message = wirepas_messaging.gateway.GenericMessage() response = message.wirepas.upload_scratchpad_resp response.header.CopyFrom(self._make_response_header()) - return message.SerializeToString() + return message From f4f153b6d8039095259eb49159e1aa2a784ebe19 Mon Sep 17 00:00:00 2001 From: Gwendal Raoul Date: Thu, 30 Jul 2020 18:18:27 +0200 Subject: [PATCH 2/2] Add Collection message: - add it in the proto file - add its support in the python api --- .../generic_message.proto | 11 ++- .../tests/gateway/test_generic_collection.py | 44 +++++++++++ .../wirepas_messaging/gateway/api/__init__.py | 1 + .../gateway/api/generic_collection.py | 73 +++++++++++++++++++ 4 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 wrappers/python/tests/gateway/test_generic_collection.py create mode 100644 wrappers/python/wirepas_messaging/gateway/api/generic_collection.py diff --git a/gateway_to_backend/protocol_buffers_files/generic_message.proto b/gateway_to_backend/protocol_buffers_files/generic_message.proto index 010c358..7304ef9 100644 --- a/gateway_to_backend/protocol_buffers_files/generic_message.proto +++ b/gateway_to_backend/protocol_buffers_files/generic_message.proto @@ -34,4 +34,13 @@ message CustomerMessage { message GenericMessage { optional WirepasMessage wirepas = 1; optional CustomerMessage customer = 2; -} \ No newline at end of file +} + +// This Generic Message collection allows a gateway, or a backend +// to group multiple message together to be transmitted as single mqtt +// message. +// It can only happen on collection topics to avoid mismatch with single +// message topic +message GenericMessageCollection { + repeated GenericMessage generic = 1; +} diff --git a/wrappers/python/tests/gateway/test_generic_collection.py b/wrappers/python/tests/gateway/test_generic_collection.py new file mode 100644 index 0000000..c841523 --- /dev/null +++ b/wrappers/python/tests/gateway/test_generic_collection.py @@ -0,0 +1,44 @@ +# flake8: noqa + +from wirepas_messaging.gateway.api import * +from default_value import * + + +def test_generate_parse_collection(): + + event1 = ReceivedDataEvent( + GATEWAY_ID, + SINK_ID, + RX_TIME_MS_EPOCH, + SOURCE_ADD, + DESTINATION_ADD, + SOURCE_EP, + DESTINATION_EP, + TRAVEL_TIME_MS, + QOS, + DATA_PAYLOAD, + hop_count=HOP_COUNT, + ) + + event2 = ReceivedDataEvent( + GATEWAY_ID, + SINK_ID, + RX_TIME_MS_EPOCH + 10, + SOURCE_ADD, + DESTINATION_ADD, + SOURCE_EP, + DESTINATION_EP, + TRAVEL_TIME_MS, + QOS, + DATA_PAYLOAD, + hop_count=HOP_COUNT, + ) + + message_list = [event1, event2] + + collection = GenericCollection(message_list) + + collection2 = GenericCollection.from_payload(collection.payload) + + for message in collection2.messages: + assert isinstance(message, ReceivedDataEvent) diff --git a/wrappers/python/wirepas_messaging/gateway/api/__init__.py b/wrappers/python/wirepas_messaging/gateway/api/__init__.py index cb0d6d5..95897bc 100644 --- a/wrappers/python/wirepas_messaging/gateway/api/__init__.py +++ b/wrappers/python/wirepas_messaging/gateway/api/__init__.py @@ -24,3 +24,4 @@ from .gateway_result_code import * from .otap_helper import * from .wirepas_exceptions import * +from .generic_collection import * diff --git a/wrappers/python/wirepas_messaging/gateway/api/generic_collection.py b/wrappers/python/wirepas_messaging/gateway/api/generic_collection.py new file mode 100644 index 0000000..98134e6 --- /dev/null +++ b/wrappers/python/wirepas_messaging/gateway/api/generic_collection.py @@ -0,0 +1,73 @@ +""" + Generic collection + ============= + + .. Copyright: + Copyright 2020 Wirepas Ltd under Apache License, Version 2.0. + See file LICENSE for full license details. +""" +# flake8: noqa +from wirepas_messaging.gateway.api import * + + +class GenericCollection(object): + """ + GenericCollection: collection of Generic message + + """ + + field_to_class = { + "status_event": StatusEvent, + "get_configs_req": GetConfigsRequest, + "get_configs_resp": GetConfigsResponse, + "set_config_req": SetConfigRequest, + "set_config_resp": SetConfigResponse, + "send_packet_req": SendDataRequest, + "send_packet_resp": SendDataResponse, + "packet_received_event": ReceivedDataEvent, + "get_scratchpad_status_req": GetScratchpadStatusRequest, + "get_scratchpad_status_resp": GetScratchpadStatusResponse, + "upload_scratchpad_req": UploadScratchpadRequest, + "upload_scratchpad_resp": UploadScratchpadResponse, + "process_scratchpad_req": ProcessScratchpadRequest, + "process_scratchpad_resp": ProcessScratchpadResponse, + "get_gateway_info_req": GetGatewayInfoRequest, + "get_gateway_info_res": GetGatewayInfoResponse, + } + + def __init__(self, generic_messages_list, **kwargs): + self.generic_messages_list = generic_messages_list + + @classmethod + def from_payload(cls, payload): + message_collection = wirepas_messaging.gateway.GenericMessageCollection() + try: + message_collection.ParseFromString(payload) + except Exception: + # Any Exception is promoted to Generic API exception + raise GatewayAPIParsingException("Cannot parse Generic payload collection") + + msgs_list = [] + for message in message_collection.generic: + for field, class_holder in GenericCollection.field_to_class.items(): + if message.wirepas.HasField(field): + msgs_list.append(class_holder.from_generic_message(message)) + break + + return cls(msgs_list) + + @property + def payload(self): + message_collection = wirepas_messaging.gateway.GenericMessageCollection() + # Add all messages one by one + for message in self.generic_messages_list: + message_collection.generic.append(message.generic_message) + + return message_collection.SerializeToString() + + @property + def messages(self): + return self.generic_messages_list + + def add_message(self, message): + self.generic_messages_list.append(message)