Exemple #1
0
    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)
Exemple #2
0
    def _handle_client_reboot(self, req: Request):
        """
        Handles a client reboot request

        :param req: Request containing the client id to reboot
        :return: None
        """
        try:
            self._validator.validate(req.get_payload(), "api_client_reboot_request")
        except ValidationError:
            self._respond_with_error(req, "ValidationError",
                                     f"Request validation error at '{ApiURIs.update_gadget.uri}'")
            return
        try:
            self.send_client_reboot(req.get_payload()["id"])
        except UnknownClientException:
            self._respond_with_error(req,
                                     "UnknownClientException",
                                     f"Nee client with the id: {req.get_payload()['id']} exists")
        except NoClientResponseException:
            self._respond_with_error(req,
                                     "NoClientResponseException",
                                     f"Client did not respond to reboot request")
        except ClientRebootError:
            self._respond_with_error(req,
                                     "ClientRebootError",
                                     f"Client could not be rebooted for some reason")
Exemple #3
0
    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)
Exemple #4
0
    def _handle_check_bridge_for_update(self, req: Request):
        """
        Checks whether the remote, the bridge is currently running on, is an older version

        :param req: empty request
        :return: None
        """
        try:
            self._validator.validate(req.get_payload(), "api_empty_request")
        except ValidationError:
            self._respond_with_error(req, "ValidationError",
                                     f"Request validation error at {ApiURIs.bridge_update_check.uri}")
            return

        encoder = ApiEncoder()
        try:
            updater = BridgeUpdateManager(os.getcwd())
            bridge_meta = updater.check_for_update()
        except UpdateNotPossibleException:
            self._respond_with_error(req, "UpdateNotPossibleException", "bridge could not be updated")
        except NoUpdateAvailableException:
            self._respond_with_status(req, True, "Bridge is up to date")
        else:
            payload = encoder.encode_bridge_update_info(bridge_meta)
            req.respond(payload)
            return
Exemple #5
0
    def _handle_get_all_configs(self, req: Request):
        """
        Responds with the names and descriptions of all available configs

        :param req: empty Request
        :return: None
        """
        try:
            self._validator.validate(req.get_payload(), "api_empty_request")
        except ValidationError:
            self._respond_with_error(req, "ValidationError",
                                     f"Request validation error at '{ApiURIs.config_storage_get_all.uri}'")
            return

        manager = ClientConfigManager()
        config_names = manager.get_config_names()
        all_configs = {}
        self._logger.info("fetching all configs")
        for config in config_names:
            if not config == "Example":
                try:
                    conf = manager.get_config(config)
                    all_configs[config] = conf["description"]
                except ConfigDoesNotExistException:
                    self._logger.error("congratz, something went wrong, abort, abort, return to the moon base")
                    pass
            else:
                pass
        payload = {"configs": all_configs}
        req.respond(payload)
Exemple #6
0
 def _log_request(self, req: Request):
     short_json = json.dumps(req.get_payload())
     if len(short_json) > 35:
         short_json = short_json[:35] + f"... + {len(short_json) - 35} bytes"
     auth_type = "No Auth" if req.get_auth() is None else req.get_auth().__class__.__name__[:-13]
     self._logger.info(f"Received request from '{req.get_sender()}' at '{req.get_path()}' "
                       f"(Auth type: '{auth_type}'): {short_json}")
    def receive(self, req: Request):
        if req.get_receiver() == self._network.get_hostname():  # Normal Request
            self._logger.info(f"Received Request at '{req.get_path()}'")
        elif req.get_receiver() is None:  # Broadcast
            self._logger.info(f"Received Broadcast at '{req.get_path()}'")
        else:
            return

        req.respond(req.get_payload())
Exemple #8
0
    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)
Exemple #9
0
    def _handle_split_request(self,
                              received_request: Request) -> Optional[Request]:
        req_payload = received_request.get_payload()
        id_str = str(received_request.get_session_id())
        p_index = req_payload["package_index"]
        split_payload = req_payload["split_payload"]
        if p_index == 0:
            if "last_index" in req_payload:
                l_index = req_payload["last_index"]
                buf_json = {
                    "start_req": received_request,
                    "last_index": l_index,
                    "payload_bits": []
                }
                for i in range(l_index + 1):
                    buf_json["payload_bits"].append(None)
                buf_json["payload_bits"][0] = split_payload
                self._part_data[id_str] = buf_json
            else:
                self._logger.error(
                    "Received first block of split request without last_index")
        else:
            if id_str in self._part_data:
                req_data = self._part_data[id_str]
                req_data["payload_bits"][p_index] = split_payload
                if p_index >= req_data["last_index"] - 1:
                    # TODO: Split requests should be recognized whether the last package is received last or not
                    end_data = ""
                    for str_data in req_data["payload_bits"]:
                        if str_data is None:
                            self._logger.error(
                                "Detected missing data block in split request")
                            break
                        end_data += str_data
                    try:
                        end_data = end_data.replace("$*$", '"')
                        json_data = json.loads(end_data)
                        first_req: Request = req_data["start_req"]

                        out_req = Request(first_req.get_path(),
                                          first_req.get_session_id(),
                                          first_req.get_sender(),
                                          first_req.get_receiver(), json_data)

                        out_req.set_callback_method(first_req.get_callback())
                        del self._part_data[id_str]
                        return out_req

                    except json.decoder.JSONDecodeError:
                        self._logger.error("Received illegal payload")

            else:
                self._logger.error(
                    "Received a followup-block with no entry in storage")
        return None
Exemple #10
0
    def _handle_get_config(self, req: Request):
        """
        Responds with the config for a given name, if there is none an error is returned

        :param req: Request containing the name of the requested config
        :return: None
        """
        try:
            self._validator.validate(req.get_payload(), "api_config_delete_get")
        except ValidationError:
            self._respond_with_error(req, "ValidationError",
                                     f"Request validation error at '{ApiURIs.config_storage_get.uri}'")
            return

        try:
            name = req.get_payload()["name"]
            config = ClientConfigManager().get_config(name)
            payload = {"config": config}
            req.respond(payload)
        except ConfigDoesNotExistException as err:
            self._respond_with_error(req=req, err_type="ConfigDoesNotExistException", message=err.args[0])
Exemple #11
0
 def _handle_client_config_delete(self, req: Request):
     """
     Handles a client config delete request
     :param req: Request containing the client config to delete
     :return: None
     """
     try:
         self._validator.validate(req.get_payload(), "api_client_config_delete")
     except ValidationError:
         self._respond_with_error(req, "ValidationError",
                                  f"Request validation error at '{ApiURIs.update_gadget.uri}'")
         return
Exemple #12
0
    def _handle_delete_config(self, req: Request):
        """
        Deletes the config for a given name, if there is no config, an error is returned

        :param req: Request containing name of the config
        :return: None
        """
        try:
            self._validator.validate(req.get_payload(), "api_config_delete_get")
        except ValidationError:
            self._respond_with_error(req, "ValidationError",
                                     f"Request validation error at '{ApiURIs.config_storage_delete.uri}'")
            return

        name = req.get_payload()["name"]
        manager = ClientConfigManager()
        try:
            manager.delete_config_file(name)
        except ConfigDoesNotExistException as err:
            self._respond_with_error(req=req, err_type="ConfigDoesNotExistException", message=err.args[0])
            return
        self._respond_with_status(req, True, "Config was deleted successfully")
Exemple #13
0
    def _handle_save_config(self, req: Request):
        """
        Saves the given config or overwrites an already existing config

        :param req: Request containing the config
        :return: None
        """
        try:
            self._validator.validate(req.get_payload(), "api_config_save")
        except ValidationError:
            self._respond_with_error(req, "ValidationError",
                                     f"Request validation error at '{ApiURIs.config_storage_save.uri}'")
            return

        config = req.get_payload()["config"]
        overwrite = req.get_payload()["overwrite"]
        manager = ClientConfigManager()
        try:
            manager.write_config(config, overwrite=overwrite)
        except ConfigAlreadyExistsException as err:
            self._respond_with_error(req=req, err_type="ConfigAlreadyExistsException", message=err.args[0])
            return
        self._respond_with_status(req, True, "Config was saved successfully")
Exemple #14
0
    def _handle_bridge_update(self, req: Request):
        """
        Updates the Bridge to a newer version or another remote, remote has to be specified in request

        :param req: empty Request
        :return: None
        """
        try:
            self._validator.validate(req.get_payload(), "api_empty_request")
        except ValidationError:
            self._respond_with_error(req, "ValidationError",
                                     f"Request validation error at {ApiURIs.bridge_update_execute.uri}")
            return

        try:
            updater = BridgeUpdateManager(os.getcwd())
            updater.execute_update()
            self._respond_with_status(req, True, "Update was successful, rebooting system now...")
            updater.reboot()
        except UpdateNotSuccessfulException:
            self._respond_with_error(req, "UpdateNotSuccessfulException", "Update failed for some reason")
Exemple #15
0
 def handle(self, req: Request) -> Optional[Request]:
     req_payload = req.get_payload()
     if "package_index" in req_payload and "split_payload" in req_payload:
         return self._handle_split_request(req)
     else:
         return req
Exemple #16
0
    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