From f9a99ce01318902b2235a99a509489d436ee56f2 Mon Sep 17 00:00:00 2001 From: Niklas Jensen Date: Sun, 25 Jan 2026 19:54:59 +0100 Subject: [PATCH] Make /api/files/... to proto endpoints --- .../system/filesystem/FileSystem.svelte | 32 +++++++++------- esp32/include/filesystem.h | 6 +-- esp32/src/filesystem.cpp | 37 ++++++++++++------- esp32/src/main.cpp | 6 +-- platform_shared/api.proto | 11 ++++++ 5 files changed, 58 insertions(+), 34 deletions(-) diff --git a/app/src/routes/system/filesystem/FileSystem.svelte b/app/src/routes/system/filesystem/FileSystem.svelte index 32e51da..6a3c916 100644 --- a/app/src/routes/system/filesystem/FileSystem.svelte +++ b/app/src/routes/system/filesystem/FileSystem.svelte @@ -6,6 +6,8 @@ import { modals } from 'svelte-modals' import NewFolderDialog from './NewFolderDialog.svelte' import NewFileDialog from './NewFileDialog.svelte' + import { api } from '$lib/api' + import type { Response } from '$lib/platform_shared/api' let currentPath = $state('/') let files = $state>([]) @@ -87,16 +89,17 @@ error = '' try { const filePath = currentPath === '/' ? `/${selectedFile}` : `${currentPath}/${selectedFile}` - const encoder = new TextEncoder() - const data = encoder.encode(fileContent) + const content = new TextEncoder().encode(fileContent) - const result = await fileSystemClient.uploadFile(filePath, data) + const result = await api.post_proto('/api/files/edit', { + fileEditRequest: { path: filePath, content } + }) - if (result.success) { + if (result.ok && result.value.statusCode === 200) { isEditing = false await loadDirectory() // Refresh to update file sizes } else { - error = result.error || 'Failed to save file' + error = result.ok ? result.value.errorMessage || 'Failed to save file' : 'Failed to save file' } } catch (e) { error = e instanceof Error ? e.message : 'Failed to save file' @@ -189,11 +192,14 @@ const path = currentPath === '/' ? `/${folderName}` : `${currentPath}/${folderName}` try { - const result = await fileSystemClient.createDirectory(path) - if (result.success) { + const result = await api.post_proto('/api/files/mkdir', { + fileMkdirRequest: { path } + }) + + if (result.ok && result.value.statusCode === 200) { await loadDirectory() } else { - error = result.error || 'Failed to create directory' + error = result.ok ? result.value.errorMessage || 'Failed to create directory' : 'Failed to create directory' } } catch (e) { error = e instanceof Error ? e.message : 'Error creating directory' @@ -207,15 +213,15 @@ const path = currentPath === '/' ? `/${fileName}` : `${currentPath}/${fileName}` try { - const encoder = new TextEncoder() - const data = encoder.encode('{}') // Default empty JSON + const result = await api.post_proto('/api/files/edit', { + fileEditRequest: { path, content: new Uint8Array(0) } + }) - const result = await fileSystemClient.uploadFile(path, data) - if (result.success) { + if (result.ok && result.value.statusCode === 200) { await loadDirectory() await loadFileContent(fileName) } else { - error = result.error || 'Failed to create file' + error = result.ok ? result.value.errorMessage || 'Failed to create file' : 'Failed to create file' } } catch (e) { error = e instanceof Error ? e.message : 'Error creating file' diff --git a/esp32/include/filesystem.h b/esp32/include/filesystem.h index 84f2f7f..cfc7650 100644 --- a/esp32/include/filesystem.h +++ b/esp32/include/filesystem.h @@ -21,13 +21,13 @@ namespace FileSystem { void listFilesProto(const std::string &directory, api_FileEntry *entry); std::string listFiles(const std::string &directory, bool isRoot = true); bool deleteFile(const char *filename); -bool editFile(const char *filename, const char *content); +bool editFile(const char *filename, const uint8_t *content, size_t size); esp_err_t getFilesProto(httpd_req_t *request); esp_err_t getFiles(httpd_req_t *request); esp_err_t getConfigFile(httpd_req_t *request); esp_err_t handleDelete(httpd_req_t *request, const api_FileDeleteRequest &req); -esp_err_t handleEdit(httpd_req_t *request, JsonVariant &json); -esp_err_t mkdir(httpd_req_t *request, JsonVariant &json); +esp_err_t handleEdit(httpd_req_t *request, const api_FileEditRequest &req); +esp_err_t mkdir(httpd_req_t *request, const api_FileMkdirRequest &req); } // namespace FileSystem diff --git a/esp32/src/filesystem.cpp b/esp32/src/filesystem.cpp index 96880d6..278ecda 100644 --- a/esp32/src/filesystem.cpp +++ b/esp32/src/filesystem.cpp @@ -124,15 +124,17 @@ esp_err_t handleDelete(httpd_req_t *request, const api_FileDeleteRequest &req) { } } -esp_err_t handleEdit(httpd_req_t *request, JsonVariant &json) { - if (json.is()) { - const char *filename = json["file"].as(); - const char *content = json["content"].as(); - ESP_LOGI(TAG, "Editing file: %s", filename); - return editFile(filename, content) ? WebServer::sendOk(request) - : WebServer::sendError(request, 500, "Edit failed"); +esp_err_t handleEdit(httpd_req_t *request, const api_FileEditRequest &req) { + ESP_LOGI(TAG, "Editing file: %s", req.path); + + api_Response res = api_Response_init_zero; + if (editFile(req.path, req.content->bytes, req.content->size)) { + res.status_code = 200; + res.which_payload = api_Response_empty_message_tag; + return WebServer::sendProto(request, 200, res, api_Response_fields); + } else { + return WebServer::sendError(request, 500, "Edit failed"); } - return WebServer::sendError(request, 400, "Invalid request"); } bool deleteFile(const char *filename) { return ESP_FS.remove(filename); } @@ -167,19 +169,26 @@ std::string listFiles(const std::string &directory, bool isRoot) { return output; } -bool editFile(const char *filename, const char *content) { +bool editFile(const char *filename, const uint8_t *content, size_t size) { File file = ESP_FS.open(filename, FILE_WRITE); if (!file) return false; - file.print(content); + file.write(content, size); file.close(); return true; } -esp_err_t mkdir(httpd_req_t *request, JsonVariant &json) { - const char *path = json["path"].as(); - ESP_LOGI(TAG, "Creating directory: %s", path); - return ESP_FS.mkdir(path) ? WebServer::sendOk(request) : WebServer::sendError(request, 500, "mkdir failed"); +esp_err_t mkdir(httpd_req_t *request, const api_FileMkdirRequest &req) { + ESP_LOGI(TAG, "Creating directory: %s", req.path); + + api_Response res = api_Response_init_zero; + if (ESP_FS.mkdir(req.path)) { + res.status_code = 200; + res.which_payload = api_Response_empty_message_tag; + return WebServer::sendProto(request, 200, res, api_Response_fields); + } else { + return WebServer::sendError(request, 500, "mkdir failed"); + } } } // namespace FileSystem diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index 558d322..eef24d9 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -106,10 +106,8 @@ void setupServer() { server.on("/api/config/*", HTTP_GET, [](httpd_req_t *request) { return FileSystem::getConfigFile(request); }); server.on("/api/files", HTTP_GET, [&](httpd_req_t *request) { return FileSystem::getFilesProto(request); }); PROTO_ENDPOINT(server, "/api/files/delete", file_delete_request, FileSystem::handleDelete); - server.on("/api/files/edit", HTTP_POST, - [&](httpd_req_t *request, JsonVariant &json) { return FileSystem::handleEdit(request, json); }); - server.on("/api/files/mkdir", HTTP_POST, - [&](httpd_req_t *request, JsonVariant &json) { return FileSystem::mkdir(request, json); }); + PROTO_ENDPOINT(server, "/api/files/edit", file_edit_request, FileSystem::handleEdit); + PROTO_ENDPOINT(server, "/api/files/mkdir", file_mkdir_request, FileSystem::mkdir); #if EMBED_WEBAPP mountStaticAssets(server); #endif diff --git a/platform_shared/api.proto b/platform_shared/api.proto index 5b7a531..750f09d 100644 --- a/platform_shared/api.proto +++ b/platform_shared/api.proto @@ -84,6 +84,15 @@ message FileDeleteRequest { string path = 1; } +message FileEditRequest { + string path = 1; + bytes content = 2; +} + +message FileMkdirRequest { + string path = 1; +} + // ============================================================================= // REST API wrappers - used by HTTP endpoints // ============================================================================= @@ -98,6 +107,8 @@ message Request { ServoSettingsRequest servo_settings_request = 21; FileListRequest file_list_request = 30; FileDeleteRequest file_delete_request = 31; + FileEditRequest file_edit_request = 32; + FileMkdirRequest file_mkdir_request = 33; } }