Пример #1
0
 async def _handle_job_request(self,
                               web_request: WebRequest) -> Dict[str, Any]:
     action = web_request.get_action()
     if action == "POST":
         files: Union[List[str], str] = web_request.get('filenames')
         if isinstance(files, str):
             files = [f.strip() for f in files.split(',') if f.strip()]
         # Validate that all files exist before queueing
         await self.queue_job(files)
     elif action == "DELETE":
         if web_request.get_boolean("all", False):
             await self.delete_job([], all=True)
         else:
             job_ids: Union[List[str], str] = web_request.get('job_ids')
             if isinstance(job_ids, str):
                 job_ids = [
                     f.strip() for f in job_ids.split(',') if f.strip()
                 ]
             await self.delete_job(job_ids)
     else:
         raise self.server.error(f"Invalid action: {action}")
     return {
         'queued_jobs': self._job_map_to_list(),
         'queue_state': self.queue_state
     }
Пример #2
0
 async def _handle_item_request(self,
                                web_request: WebRequest) -> Dict[str, Any]:
     action = web_request.get_action()
     namespace = web_request.get_str("namespace")
     if namespace in self.forbidden_namespaces:
         raise self.server.error(
             f"Read/Write access to namespace '{namespace}'"
             " is forbidden", 403)
     key: Any
     valid_types: Tuple[type, ...]
     if action != "GET":
         if namespace in self.protected_namespaces:
             raise self.server.error(
                 f"Write access to namespace '{namespace}'"
                 " is forbidden", 403)
         key = web_request.get("key")
         valid_types = (list, str)
     else:
         key = web_request.get("key", None)
         valid_types = (list, str, type(None))
     if not isinstance(key, valid_types):
         raise self.server.error(
             "Value for argument 'key' is an invalid type: "
             f"{type(key).__name__}")
     if action == "GET":
         val = await self.get_item(namespace, key)
     elif action == "POST":
         val = web_request.get("value")
         await self.insert_item(namespace, key, val)
     elif action == "DELETE":
         val = await self.delete_item(namespace, key, drop_empty_db=True)
     return {'namespace': namespace, 'key': key, 'value': val}
Пример #3
0
 async def _handle_update_request(self,
                                  web_request: WebRequest
                                  ) -> str:
     await self.initialized_lock.wait()
     if await self._check_klippy_printing():
         raise self.server.error("Update Refused: Klippy is printing")
     app: str = web_request.get_endpoint().split("/")[-1]
     if app == "client":
         app = web_request.get('name')
     if self.cmd_helper.is_app_updating(app):
         return f"Object {app} is currently being updated"
     updater = self.updaters.get(app, None)
     if updater is None:
         raise self.server.error(f"Updater {app} not available", 404)
     async with self.cmd_request_lock:
         self.cmd_helper.set_update_info(app, id(web_request))
         try:
             if not await self._check_need_reinstall(app):
                 await updater.update()
         except Exception as e:
             self.cmd_helper.notify_update_response(
                 f"Error updating {app}")
             self.cmd_helper.notify_update_response(
                 str(e), is_complete=True)
             raise
         finally:
             self.cmd_helper.clear_update_info()
     return "ok"
Пример #4
0
 async def _handle_update_request(
     self, web_request: WebRequest
 ) -> Dict[str, Any]:
     subs: Optional[Union[str, List[str]]]
     subs = web_request.get("subscriptions", None)
     if isinstance(subs, str):
         subs = [sub.strip() for sub in subs.split(",") if sub.strip()]
     elif subs is None:
         subs = list(self.subscriptions.keys())
     for sub in subs:
         if sub not in self.subscriptions:
             raise self.server.error(f"No subscription for {sub}")
     async with self.request_lock:
         changed = False
         for sub in subs:
             ret = await self.subscriptions[sub].update_entries()
             changed |= ret
         entries = await self.entry_mgr.list_entries()
         if changed:
             self.eventloop.delay_callback(
                 .05, self.server.send_event,
                 "announcements:entries_updated",
                 {"entries": entries})
         return {
             "entries": entries,
             "modified": changed
         }
Пример #5
0
 async def _select_file(self,
                        web_request: WebRequest
                        ) -> None:
     command: str = web_request.get('command')
     rel_path: str = web_request.get('relative_path')
     root, filename = rel_path.strip("/").split("/", 1)
     fmgr: FileManager = self.server.lookup_component('file_manager')
     if command == "select":
         start_print: bool = web_request.get('print', False)
         if not start_print:
             # No-op, selecting a file has no meaning in Moonraker
             return
         if root != "gcodes":
             raise self.server.error(
                 "File must be located in the 'gcodes' root", 400)
         if not fmgr.check_file_exists(root, filename):
             raise self.server.error("File does not exist")
         try:
             ret = await self.klippy_apis.query_objects(
                 {'print_stats': None})
             pstate: str = ret['print_stats']['state']
         except self.server.error:
             pstate = "not_avail"
         started: bool = False
         if pstate not in ["printing", "paused", "not_avail"]:
             try:
                 await self.klippy_apis.start_print(filename)
             except self.server.error:
                 started = False
             else:
                 logging.debug(f"Job '{filename}' started via Octoprint API")
                 started = True
         if not started:
             if fmgr.upload_queue_enabled():
                 job_queue: JobQueue = self.server.lookup_component(
                     'job_queue')
                 await job_queue.queue_job(filename, check_exists=False)
                 # Fire the file_manager's upload_queued event for
                 # compatibility.  We assume that this endpoint is
                 # requests by Cura after a file has been uploaded.
                 self.server.send_event("file_manager:upload_queued",
                                        filename)
                 logging.debug(f"Job '{filename}' queued via Octoprint API")
             else:
                 raise self.server.error("Conflict", 409)
     else:
         raise self.server.error(f"Unsupported Command: {command}")
Пример #6
0
 async def _handle_call_agent(self, web_request: WebRequest) -> Any:
     agent = web_request.get_str("agent")
     method: str = web_request.get_str("method")
     args: Optional[Union[List, Dict[str, Any]]]
     args = web_request.get("arguments", None)
     if args is not None and not isinstance(args, (list, dict)):
         raise self.server.error(
             "The 'arguments' field must contain an object or a list")
     if agent not in self.agents:
         raise self.server.error(f"Agent {agent} not connected")
     conn = self.agents[agent]
     return await conn.call_method(method, args)
Пример #7
0
 async def _handle_publish_request(
         self, web_request: WebRequest) -> Dict[str, Any]:
     topic: str = web_request.get_str("topic")
     payload: Any = web_request.get("payload", None)
     qos: int = web_request.get_int("qos", self.qos)
     retain: bool = web_request.get_boolean("retain", False)
     timeout: Optional[float] = web_request.get_float('timeout', None)
     try:
         await asyncio.wait_for(
             self.publish_topic(topic, payload, qos, retain), timeout)
     except asyncio.TimeoutError:
         raise self.server.error("MQTT Publish Timed Out", 504)
     return {"topic": topic}
Пример #8
0
    async def _post_command(self, web_request: WebRequest) -> Dict:
        """
        Request to run some gcode command
        """
        commands: List[str] = web_request.get('commands', [])
        for command in commands:
            logging.info(f'Executing GCode: {command}')
            try:
                await self.klippy_apis.run_gcode(command)
            except self.server.error:
                msg = f"Error executing GCode {command}"
                logging.exception(msg)

        return {}
Пример #9
0
 async def _handle_feed_request(
     self, web_request: WebRequest
 ) -> Dict[str, Any]:
     action = web_request.get_action()
     name: str = web_request.get("name")
     name = name.lower()
     changed: bool = False
     db: MoonrakerDatabase = self.server.lookup_component("database")
     result = "skipped"
     if action == "POST":
         if name not in self.subscriptions:
             feed = RssFeed(name, self.entry_mgr, self.dev_mode)
             self.subscriptions[name] = feed
             await feed.initialize()
             changed = await feed.update_entries()
             self.stored_feeds.append(name)
             db.insert_item(
                 "moonraker", "announcements.stored_feeds", self.stored_feeds
             )
             result = "added"
     elif action == "DELETE":
         if name not in self.stored_feeds:
             raise self.server.error(f"Feed '{name}' not stored")
         if name in self.configured_feeds:
             raise self.server.error(
                 f"Feed '{name}' exists in the configuration, cannot remove"
             )
         self.stored_feeds.remove(name)
         db.insert_item(
             "moonraker", "announcements.stored_feeds", self.stored_feeds
         )
         if name in self.subscriptions:
             del self.subscriptions[name]
             changed = await self.entry_mgr.prune_by_feed(name)
             logging.info(f"Removed Announcement Feed: {name}")
             result = "removed"
         else:
             raise self.server.error(f"Feed does not exist: {name}")
     if changed:
         entries = await self.entry_mgr.list_entries()
         self.eventloop.delay_callback(
             .05, self.server.send_event, "announcements:entries_updated",
             {"entries": entries}
         )
     return {
         "feed": name,
         "action": result
     }
Пример #10
0
 async def _handle_service_request(self, web_request: WebRequest) -> str:
     name: str = web_request.get('service')
     action = web_request.get_endpoint().split('/')[-1]
     if name == "moonraker":
         if action != "restart":
             raise self.server.error(
                 f"Service action '{action}' not available for moonraker")
         event_loop = self.server.get_event_loop()
         event_loop.register_callback(self.do_service_action, action, name)
     elif self.sys_provider.is_service_available(name):
         await self.do_service_action(action, name)
     else:
         if name in ALLOWED_SERVICES:
             raise self.server.error(f"Service '{name}' not installed")
         raise self.server.error(f"Service '{name}' not allowed")
     return "ok"
Пример #11
0
 async def _handle_service_request(self, web_request: WebRequest) -> str:
     name: str = web_request.get('service')
     action = web_request.get_endpoint().split('/')[-1]
     if name == "moonraker":
         if action != "restart":
             raise self.server.error(
                 f"Service action '{action}' not available for moonraker")
         IOLoop.current().spawn_callback(self.do_service_action, action,
                                         name)
     elif name in self.available_services:
         await self.do_service_action(action, name)
     else:
         if name in ALLOWED_SERVICES and \
                 name not in self.available_services:
             raise self.server.error(f"Service '{name}' not installed")
         raise self.server.error(f"Service '{name}' not allowed")
     return "ok"
Пример #12
0
 async def _handle_agent_event(self, web_request: WebRequest) -> str:
     conn = web_request.get_connection()
     if not isinstance(conn, WebSocket):
         raise self.server.error("No connection detected")
     if conn.client_data["type"] != "agent":
         raise self.server.error(
             "Only connections of the 'agent' type can send events")
     name = conn.client_data["name"]
     evt_name = web_request.get_str("event")
     if evt_name in ["connected", "disconnected"]:
         raise self.server.error(f"Event '{evt_name}' is reserved")
     data: Optional[Union[List, Dict[str, Any]]]
     data = web_request.get("data", None)
     evt: Dict[str, Any] = {"agent": name, "event": evt_name}
     if data is not None:
         evt["data"] = data
     conn.send_notification("agent_event", [evt])
     return "ok"