def _handle_client_sync(self, req: Request): """ Handles a client update request from any foreign source :param req: Request containing the client update request :return: None """ try: self._validator.validate(req.get_payload(), "api_client_sync_request") except ValidationError as err: self._respond_with_error(req, "ValidationError", f"Request validation error at '{ApiURIs.sync_client.uri}': '{err.message}'") return client_id = req.get_sender() self._logger.info(f"Syncing client {client_id}") decoder = ApiDecoder() new_client = decoder.decode_client(req.get_payload()["client"], req.get_sender()) gadget_data = req.get_payload()["gadgets"] for gadget in gadget_data: self._update_gadget(client_id, gadget) self._delegate.handle_client_sync(new_client)
def _handle_heartbeat(self, req: Request): try: self._validator.validate(req.get_payload(), "bridge_heartbeat_request") except ValidationError: self._respond_with_error(req, "ValidationError", f"Request validation error at '{ApiURIs.heartbeat.uri}'") return rt_id = req.get_payload()["runtime_id"] self._delegate.handle_heartbeat(req.get_sender(), rt_id)
def _handle_update_gadget(self, req: Request): """ Handles a characteristic update request, for a gadget, from any foreign source :param req: Request containing the gadget update request :return: None """ try: self._validator.validate(req.get_payload(), "api_gadget_update_request") except ValidationError: self._respond_with_error(req, "ValidationError", f"Request validation error at '{ApiURIs.update_gadget.uri}'") return try: gadget_update_info = ApiDecoder().decode_gadget_update(req.get_payload()) except GadgetDecodeError: self._respond_with_error(req, "GadgetDecodeError", f"Gadget update decode error at '{ApiURIs.sync_client.uri}'") return client_id = req.get_sender() gadget_info = [x for x in self._delegate.get_gadget_info() if x.get_name() == req.get_payload()["id"]] if not gadget_info: self._respond_with_error(req, "GagdetDoesNeeExist", "Sadly, no gadget with the given id exists") return gadget = gadget_info[0] updated_characteristics = [x.id for x in gadget_update_info.characteristics] buf_characteristics = [x for x in gadget.get_characteristics() if x.get_type() in updated_characteristics] for c in buf_characteristics: value = [x.step_value for x in gadget_update_info.characteristics if x.id == c.get_type()][0] c.set_step_value(value) out_gadget = AnyGadget(gadget_update_info.id, req.get_sender(), buf_characteristics) self._logger.info(f"Updating {len(buf_characteristics)} gadget characteristics from '{client_id}'") self._delegate.handle_gadget_update(out_gadget)
def mock_response_function(req: Request, payload: dict, path: str): if path is None: buf_path = req.get_path() else: buf_path = path out_req = Request(path=buf_path, session_id=req.get_session_id(), sender=req.get_receiver(), receiver=req.get_sender(), payload=payload) self._last_response = out_req
def _respond_to(self, req: Request, payload: dict, path: Optional[str] = None): if path: out_path = path else: out_path = req.get_path() receiver = req.get_sender() out_req = Request(out_path, req.get_session_id(), self._host_name, receiver, payload) self._send(out_req)
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)
def wait_for_responses(self, out_req: Request, timeout: int = 5, max_resp_count: Optional[int] = 1) -> list[Request]: if not self._keep_queue: self._request_queue = Queue() else: self._keep_queue = False responses: list[Request] = [] timeout_time = datetime.now() + timedelta(seconds=timeout) while timeout and datetime.now() < timeout_time: if max_resp_count and len( responses ) >= max_resp_count: # return responses if enough are collected return responses if not self._request_queue.empty(): res: Request = self._request_queue.get() if res.get_session_id() == out_req.get_session_id( ) and out_req.get_sender() != res.get_sender(): responses.append(res) return responses
def send_request_split(self, path: str, receiver: str, payload: dict, part_max_size: int = 30, timeout: Optional[int] = None) -> Optional[Request]: """ Sends a request to all attached networks. The request will be split into individual parts with a maximum length. :param path: Path to send the request on :param receiver: Receiver for the Request :param payload: Payload to be send :param part_max_size: Maximum size in bytes for each individual payload chunk :param timeout: Maximum timeout to wait for an answer :return: The response if there is any """ if timeout is None: timeout = self._default_timeout req = Request(path, None, self._hostname, receiver, payload) session_id = req.get_session_id() path = req.get_path() sender = req.get_sender() receiver = req.get_receiver() payload_str = json.dumps(req.get_payload()) # Make string ready to be contained in json itself payload_str = payload_str.replace('"', "$*$") payload_len = len(payload_str) parts = [] start = 0 package_index = 0 while start < payload_len: end = start + part_max_size payload_part = payload_str[start:( end if end < payload_len else payload_len)] parts.append(payload_part) start = end last_index = len(parts) for payload_part in parts: out_dict = { "package_index": package_index, "split_payload": payload_part } if package_index == 0: out_dict["last_index"] = last_index out_req = Request(path, session_id, sender, receiver, out_dict) if package_index == last_index - 1: responses = self._send_request_obj(out_req, timeout, 1) if not responses: return None return responses[0] else: self._send_request_obj(out_req, 0, 0) package_index += 1 sleep(0.1) return None
def receive(self, req: Request): if req.get_sender() not in self._clients: self._clients.append(req.get_sender())