예제 #1
0
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
예제 #2
0
    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")