From 0e79b6f3f7e9a8614c0a8f1d775ff3ca260deca8 Mon Sep 17 00:00:00 2001 From: Arksine Date: Sat, 4 Jul 2020 14:33:17 -0400 Subject: [PATCH] file_manager: add JSON-RPC "directory" APIs Signed-off-by: Eric Callahan --- docs/web_api.md | 23 +++++++++++++++++------ moonraker/plugins/file_manager.py | 9 ++++++--- moonraker/websockets.py | 2 +- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/docs/web_api.md b/docs/web_api.md index 199fbe7..9aae72c 100644 --- a/docs/web_api.md +++ b/docs/web_api.md @@ -297,9 +297,10 @@ that uses promises to return responses and errors (see json-rcp.js). ## File Operations -While all file transfer operations are available via the HTTP API, only -"get_file_list" and "get_metadata" are available over the websocket. Aside from -the log files, currently the only root available is "gcodes" (at `http:\\host\server\files\gcodes\*`), however support for other "root" +Most file operations are available over both APIs, however file upload, +file download, and file delete are currently only available via HTTP APIs. +Aside from the log files, currently the only root available is "gcodes" +(at `http:\\host\server\files\gcodes\*`), however support for other "root" directories may be added in the future. File upload, file delete, and directory manipulation(mkdir and rmdir) will only be available on the "gcodes" root. @@ -385,7 +386,11 @@ subdirectories. the "gcodes" file list by default. - Websocket command:\ - Not Available + `{jsonrpc: "2.0", method: "get_directory", params: {path: "gcodes/my_subdir"} + , id: }` + + If the "params" are omitted then the command will return + the "gcodes" file list by default. - Returns:\ An object containing file and subdirectory information in the @@ -416,7 +421,8 @@ Creates a new directory at the specified path. `POST /server/files/directory?path=gcodes/my_new_dir` - Websocket command:\ - Not Available + `{jsonrpc: "2.0", method: "post_directory", params: + {path: "gcodes/my_new_dir"}, id: }` Returns:\ `ok` if successful @@ -428,13 +434,18 @@ Deletes a directory at the specified path. `DELETE /server/files/directory?path=gcodes/my_subdir` - Websocket command:\ - Not Available + `{jsonrpc: "2.0", method: "delete_directory", params: {path: "gcodes/my_subdir"} + , id: }` If the specified directory contains files then the delete request will fail, however it is possible to "force" deletion of the directory and all files in it with and additional argument in the query string:\ `DELETE /server/files/directory?path=gcodes/my_subdir&force=true` + OR to the JSON-RPC params:\ + `{jsonrpc: "2.0", method: "get_directory", params: + {path: "gcodes/my_subdir", force: True}, id: }` + Note that a forced deletion will still check in with Klippy to be sure that a file in the requested directory is not loaded by the virtual_sdcard. diff --git a/moonraker/plugins/file_manager.py b/moonraker/plugins/file_manager.py index 05743b3..a93be30 100644 --- a/moonraker/plugins/file_manager.py +++ b/moonraker/plugins/file_manager.py @@ -30,8 +30,8 @@ class FileManager: "/server/files/metadata", "file_metadata", ['GET'], self._handle_metadata_request) self.server.register_endpoint( - "/server/files/directory", None, ['GET', 'POST', 'DELETE'], - self._handle_directory_request, http_only=True) + "/server/files/directory", "directory", ['GET', 'POST', 'DELETE'], + self._handle_directory_request) def _register_static_files(self, gcode_path): self.server.register_static_file_handler( @@ -93,7 +93,10 @@ class FileManager: if not os.path.isdir(dir_path): raise self.server.error( "Directory does not exist (%s)" % (directory)) - if args.get('force', "false").lower() == "true": + force = args.get('force', False) + if isinstance(force, str): + force = force.lower() == "true" + if force: # Make sure that the directory does not contain a file # loaded by the virtual_sdcard await self._handle_operation_check(dir_path) diff --git a/moonraker/websockets.py b/moonraker/websockets.py index e042a8e..0b8e026 100644 --- a/moonraker/websockets.py +++ b/moonraker/websockets.py @@ -138,7 +138,7 @@ class WebsocketManager: self.rpc.register_method(cmd, rpc_cb) def remove_handler(self, ws_method): - for prefix in ["get", "post"]: + for prefix in ["get", "post", "delete"]: self.rpc.remove_method(prefix + "_" + ws_method) def _generate_callback(self, endpoint, request_method):