class RestServerRequestManager: _request: Request _response: Optional[Request] def __init__(self, hostname: str, path: str, payload: dict, auth: Optional[AuthContainer]): self._response = None self._create_incoming_request(hostname, path, payload, auth) def __del__(self): pass def _create_incoming_request(self, hostname: str, path: str, payload: dict, auth: Optional[AuthContainer]): session_id = random.randint(0, 30000) sender = f"rest_client_{session_id}" self._request = Request(path=path, session_id=session_id, sender=sender, receiver=hostname, payload=payload) if auth is not None: self._request.set_auth(auth) self._request.set_callback_method(self._get_response_function()) def _get_response_function(self) -> response_callback_type: def respond(req: Request, payload: dict, path: Optional[str]): if req.get_session_id() != self._request.get_session_id(): raise IllegalResponseException( f"Session IDs {req.get_session_id()} and " f"{self._request.get_session_id()} are not matching") if path is not None: res_path = path else: res_path = req.get_path() self._response = Request(path=res_path, session_id=req.get_session_id(), sender=self._request.get_receiver(), receiver=req.get_sender(), payload=payload) return respond def get_request(self) -> Request: return self._request def await_response(self, timeout: int = 2) -> Request: start_time = datetime.now() while self._response is None: time.sleep(0.1) now = datetime.now() if now > (start_time + timedelta(seconds=timeout)): break if self._response is None: raise NoResponseReceivedError(self._request.get_path()) return self._response
def _decode_line(self, line) -> Optional[Request]: """Decodes a line and extracts a request if there is any""" if line[:3] == "!r_": elems = re.findall("_([a-z])\[(.+?)\]", line) req_dict = {} for elem_type, val in elems: if elem_type in req_dict: self._logger.warning( "Double key in request: '{}'".format(elem_type)) return None else: req_dict[elem_type] = val for key in ["p", "b"]: if key not in req_dict: self._logger.warning( "Missing key in request: '{}'".format(key)) return None try: json_body = json.loads(req_dict["b"]) try: self._validator.validate(json_body, REQ_VALIDATION_SCHEME_NAME) except ValidationError: self._logger.warning( "Could not decode Request, Schema Validation failed.") return None out_req = Request(path=req_dict["p"], session_id=json_body["session_id"], sender=json_body["sender"], receiver=json_body["receiver"], payload=json_body["payload"], connection_type=f"Serial[{self._address}]") out_req.set_auth(SerialAuthContainer()) return out_req except ValueError: return None return None
def buf_callback(client, userdata, message): """Callback to attach to mqtt object, mqtt_res_queue gets catched in closure""" topic = message.topic try: json_str = message.payload.decode("utf-8") except UnicodeDecodeError: self._logger.warning("Couldn't format json string") return try: body = json.loads(json_str) except json.decoder.JSONDecodeError: self._logger.warning( "Couldn't decode json: '{}'".format(json_str)) return try: self._validator.validate(body, REQ_VALIDATION_SCHEME_NAME) except ValidationError: self._logger.warning( "Could not decode Request, Schema Validation failed.") topic_without_channel = topic[len(self._channel):].strip("/") try: inc_req = Request(topic_without_channel, body["session_id"], body["sender"], body["receiver"], body["payload"], connection_type=f"MQTT") inc_req.set_auth(MqttAuthContainer()) inc_req.set_callback_method(self._respond_to) self._add_req_to_queue(inc_req) except ValueError: self._logger.error("Error creating Request")