# ShowenV2 HTTP API ## 基础信息 - Base URL: `http://:8080` - API 前缀: `/api` - 编码: `UTF-8` - 认证: 当前版本局域网无认证,后续版本预留 - 权威实现: `src/plugins/http/routes.rs` ## 响应约定 ### 成功响应 写操作接口统一返回: ```json { "status": "ok", "message": "开始播放" } ``` ### 错误响应 除文件下载接口外,错误统一返回: ```json { "status": "error", "message": "错误描述" } ``` 查询接口直接返回业务 JSON,不包裹 `status` 字段。 ### 典型错误码 - `400 Bad Request`: 参数、JSON、文件名或配置内容非法 - `403 Forbidden`: 文件管理路径越界或目标目录不合法 - `404 Not Found`: 文件、目录、插件或配置不存在 - `409 Conflict`: 文件移动目标已存在 - `413 Payload Too Large`: 单文件超过 100 MB - `500 Internal Server Error`: 内部发送消息失败、文件操作失败 - `502 Bad Gateway`: WiFi 插件返回无效 JSON - `504 Gateway Timeout`: 等待 WiFi 插件响应超时 ## Web UI ### GET / - Method: `GET` - Path: `/` - Request Body: 无 - Response Example: ```html Showen 控制台 ... ``` - Error Response: 标准 HTTP 错误页面,无 JSON 包装 ### GET /index.html - Method: `GET` - Path: `/index.html` - Request Body: 无 - Response Example: ```html Showen 控制台 ... ``` - Error Response: 标准 HTTP 错误页面,无 JSON 包装 ## WebSocket ### GET /ws - Method: `GET` (Upgrade to WebSocket) - Path: `/ws` - Request Body: 无 - Response Example: 连接建立后服务端会先推送当前快照,再持续推送事件 - Error Response: WebSocket 握手失败时返回标准 HTTP 错误 ### 服务端事件 #### `status_update` ```json { "type": "status_update", "data": { "running": true, "paused": false, "in_transition": false, "current_index": 0, "playlist_length": 3, "current_video": "intro" } } ``` #### `state_update` ```json { "type": "state_update", "data": { "old_state": "rest", "new_state": "interact" } } ``` #### `config_update` ```json { "type": "config_update", "data": { "display": { "fullscreen": true, "window_title": "Hologram Player - Cat", "rotation": 0, "flip_horizontal": true, "flip_vertical": true, "offset_x": 0, "offset_y": 0, "prevent_screen_lock": true, "render_width": 1280, "render_height": 800, "output_width": null, "output_height": null, "scale_mode": "stretch", "allow_upscale": true, "perspective_correction": { "enabled": false, "points": [[0, 0], [1280, 0], [1280, 800], [0, 800]] }, "chroma_key": { "enabled": false, "hsv_min": [0, 0, 200], "hsv_max": [180, 30, 255], "invert": false, "feather": 3 }, "brightness_adjust": { "enabled": true, "subject_boost": 1.5, "background_suppress": 0.3, "threshold": 30 } }, "playlist": [ { "id": "anim_0", "path": "videos/intro.mp4", "duration": null, "loop_count": 1, "random_loop_range": null } ], "transition": { "enabled": true, "type": "fade", "duration": 0.5 }, "playback": { "loop_playlist": true, "auto_start": true }, "scenes": { "rest": [], "active": [], "sleep": [], "interact": [], "state_machine": null }, "remote_control": { "enabled": true, "host": "0.0.0.0", "port": 8080 }, "ble": { "enabled": true, "device_name": "Showen" }, "source_path": "/home/showen/Showen/ShowenV2/configs/cat_state_machine.json", "source_dir": "/home/showen/Showen/ShowenV2/configs" } } ``` #### `wifi_update` ```json { "type": "wifi_update", "data": { "ok": true, "networks": [ { "ssid": "OfficeWiFi", "signal": 78, "security": "WPA2" } ] } } ``` 说明:该事件直接转发 WiFi 插件返回的 JSON,字段随具体命令而变。 #### `ble_update` ```json { "type": "ble_update", "data": { "ready": true } } ``` ### 客户端可发送命令 WebSocket 文本消息需为 JSON;成功响应格式不是 HTTP API 的 `{ "status": "ok" }`,而是 WebSocket 专用格式: ```json { "ok": true, "cmd": "play" } ``` 错误示例: ```json { "ok": false, "cmd": "goto", "error": "missing index" } ``` 已支持命令示例: ```json {"cmd":"play"} {"cmd":"pause"} {"cmd":"next"} {"cmd":"previous"} {"cmd":"goto","index":3} {"cmd":"scene","name":"rest"} {"cmd":"trigger","name":"voice","value":"name"} {"cmd":"connect","ssid":"OfficeWiFi","password":"secret"} {"cmd":"ap_start","ssid":"showen","password":"12345678"} ``` ## 播放控制 ### GET /api/status - Method: `GET` - Path: `/api/status` - Request Body: 无 - Response Example: ```json { "running": true, "paused": false, "in_transition": false, "current_index": 0, "playlist_length": 3, "current_video": "intro" } ``` - Error Response: `404/405` 由路由层处理;无业务级错误 JSON ### POST /api/play - Method: `POST` - Path: `/api/play` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "开始播放" } ``` - Error Response: `{ "status": "error", "message": "发送命令失败: ..." }` ### POST /api/pause - Method: `POST` - Path: `/api/pause` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "已暂停" } ``` - Error Response: `{ "status": "error", "message": "发送命令失败: ..." }` ### POST /api/next - Method: `POST` - Path: `/api/next` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "切换到下一个视频" } ``` - Error Response: `{ "status": "error", "message": "发送命令失败: ..." }` ### POST /api/previous - Method: `POST` - Path: `/api/previous` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "切换到上一个视频" } ``` - Error Response: `{ "status": "error", "message": "发送命令失败: ..." }` ### POST /api/goto/:index - Method: `POST` - Path: `/api/goto/:index` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "跳转到视频 2" } ``` - Error Response: `{ "status": "error", "message": "无效的视频索引" }` 或 `{ "status": "error", "message": "发送命令失败: ..." }` ### GET /api/playlist - Method: `GET` - Path: `/api/playlist` - Request Body: 无 - Response Example: ```json { "playlist": [ { "id": "anim_0", "path": "videos/intro.mp4", "duration": null, "loop_count": 1, "random_loop_range": null }, { "id": "anim_1", "path": "videos/idle.mp4", "duration": 12.5, "loop_count": 2, "random_loop_range": null } ], "current_index": 0 } ``` - Error Response: `404/405` 由路由层处理;无业务级错误 JSON ### POST /api/scene/:name - Method: `POST` - Path: `/api/scene/:name` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "切换到场景: rest" } ``` - Error Response: `{ "status": "error", "message": "发送命令失败: ..." }` ### POST /api/trigger/:name - Method: `POST` - Path: `/api/trigger/:name` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "触发器 'voice' 已发送" } ``` - Error Response: `{ "status": "error", "message": "发送命令失败: ..." }` ### POST /api/trigger/:name/:value - Method: `POST` - Path: `/api/trigger/:name/:value` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "触发器 'voice' 已发送,值: name" } ``` - Error Response: `{ "status": "error", "message": "发送命令失败: ..." }` ## 配置管理 ### GET /api/config - Method: `GET` - Path: `/api/config` - Request Body: 无 - Response Example: ```json { "display": { "fullscreen": true, "window_title": "Hologram Player - Cat", "rotation": 0, "flip_horizontal": true, "flip_vertical": true, "offset_x": 0, "offset_y": 0, "prevent_screen_lock": true, "render_width": 1280, "render_height": 800, "output_width": null, "output_height": null, "scale_mode": "stretch", "allow_upscale": true, "perspective_correction": { "enabled": false, "points": [[0, 0], [1280, 0], [1280, 800], [0, 800]] }, "chroma_key": { "enabled": false, "hsv_min": [0, 0, 200], "hsv_max": [180, 30, 255], "invert": false, "feather": 3 }, "brightness_adjust": { "enabled": true, "subject_boost": 1.5, "background_suppress": 0.3, "threshold": 30 } }, "playlist": [ { "id": "anim_0", "path": "videos/intro.mp4", "duration": null, "loop_count": 1, "random_loop_range": null } ], "transition": { "enabled": true, "type": "fade", "duration": 0.5 }, "playback": { "loop_playlist": true, "auto_start": true }, "scenes": { "rest": [], "active": [], "sleep": [], "interact": [], "state_machine": null }, "remote_control": { "enabled": true, "host": "0.0.0.0", "port": 8080 }, "ble": { "enabled": true, "device_name": "Showen" }, "source_path": "/home/showen/Showen/ShowenV2/configs/cat_state_machine.json", "source_dir": "/home/showen/Showen/ShowenV2/configs" } ``` - Error Response: `404/405` 由路由层处理;无业务级错误 JSON ### GET /api/config/display - Method: `GET` - Path: `/api/config/display` - Request Body: 无 - Response Example: ```json { "fullscreen": true, "window_title": "Hologram Player - Cat", "rotation": 0, "flip_horizontal": true, "flip_vertical": true, "offset_x": 0, "offset_y": 0, "prevent_screen_lock": true, "render_width": 1280, "render_height": 800, "output_width": null, "output_height": null, "scale_mode": "stretch", "allow_upscale": true, "perspective_correction": { "enabled": false, "points": [[0, 0], [1280, 0], [1280, 800], [0, 800]] }, "chroma_key": { "enabled": false, "hsv_min": [0, 0, 200], "hsv_max": [180, 30, 255], "invert": false, "feather": 3 }, "brightness_adjust": { "enabled": true, "subject_boost": 1.5, "background_suppress": 0.3, "threshold": 30 } } ``` - Error Response: `404/405` 由路由层处理;无业务级错误 JSON ### POST /api/config - Method: `POST` - Path: `/api/config` - Request Body Example: ```json { "display": { "fullscreen": true, "window_title": "Showen", "rotation": 0, "flip_horizontal": false, "flip_vertical": false, "offset_x": 0, "offset_y": 0, "prevent_screen_lock": true, "render_width": 1280, "render_height": 800, "output_width": null, "output_height": null, "scale_mode": "fit", "allow_upscale": true, "perspective_correction": { "enabled": false, "points": [] }, "chroma_key": { "enabled": false, "hsv_min": [0, 0, 200], "hsv_max": [180, 30, 255], "invert": false, "feather": 0 }, "brightness_adjust": { "enabled": false, "subject_boost": 1.5, "background_suppress": 0.3, "threshold": 30 } }, "playlist": [ { "id": "intro", "path": "videos/intro.mp4", "duration": null, "loop_count": 1, "random_loop_range": null } ], "transition": { "enabled": true, "type": "fade", "duration": 0.5 }, "playback": { "loop_playlist": true, "auto_start": true }, "scenes": { "rest": [], "active": [], "sleep": [], "interact": [], "state_machine": null }, "remote_control": { "enabled": true, "host": "0.0.0.0", "port": 8080 }, "ble": { "enabled": true, "device_name": "Showen" } } ``` - Response Example: ```json { "status": "ok", "message": "配置已保存,热重载将自动生效" } ``` - Error Response: `{ "status": "error", "message": "请求体不是有效的 UTF-8" }`、`{ "status": "error", "message": "配置验证失败: ..." }`、`{ "status": "error", "message": "写入配置文件失败: ..." }` ### GET /api/config/available - Method: `GET` - Path: `/api/config/available` - Request Body: 无 - Response Example: ```json { "configs": [ "cat_state_machine.json", "dog_state_machine.json" ], "active": "cat_state_machine.json" } ``` - Error Response: `404/405` 由路由层处理;无业务级错误 JSON ### POST /api/config/switch - Method: `POST` - Path: `/api/config/switch` - Request Body Example: ```json { "filename": "dog_state_machine.json" } ``` - Response Example: ```json { "status": "ok", "message": "已切换到配置: dog_state_machine.json" } ``` - Error Response: `{ "status": "error", "message": "文件名不合法" }`、`{ "status": "error", "message": "只支持 .json 配置文件" }`、`{ "status": "error", "message": "配置文件不存在" }`、`{ "status": "error", "message": "配置验证失败: ..." }` ## 视频管理 ### GET /api/videos - Method: `GET` - Path: `/api/videos` - Request Body: 无 - Response Example: ```json [ { "name": "intro.mp4", "size": 1048576 }, { "name": "subdir/idle.mp4", "size": 2097152 } ] ``` - Error Response: `404/405` 由路由层处理;无业务级错误 JSON ### POST /api/videos/upload - Method: `POST` - Path: `/api/videos/upload` - Request Body Example: `multipart/form-data`,一个或多个 `file` 字段 - Response Example: ```json { "status": "ok", "message": "已上传 2 个文件: intro.mp4, idle.mp4" } ``` - Error Response: `{ "status": "error", "message": "未找到上传文件" }`、`{ "status": "error", "message": "文件大小超过限制: 单文件最大 100 MB" }`、`{ "status": "error", "message": "保存文件失败: ..." }` ### DELETE /api/videos/:filename - Method: `DELETE` - Path: `/api/videos/:filename` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "已删除: intro.mp4" } ``` - Error Response: `{ "status": "error", "message": "无效的文件名" }`、`{ "status": "error", "message": "文件不存在" }`、`{ "status": "error", "message": "删除失败: ..." }` ## WiFi ### GET /api/wifi/status - Method: `GET` - Path: `/api/wifi/status` - Request Body: 无 - Response Example: ```json { "connected": true, "ssid": "OfficeWiFi", "ip": "192.168.1.23" } ``` - Error Response: `{ "status": "error", "message": "等待 WiFi 响应超时" }`、`{ "status": "error", "message": "WiFi 返回了无效 JSON: ..." }`、`{ "status": "error", "message": "WiFi 操作失败" }` ### GET /api/wifi/scan - Method: `GET` - Path: `/api/wifi/scan` - Request Body: 无 - Response Example: ```json [ { "ssid": "OfficeWiFi", "signal": 78, "security": "WPA2" }, { "ssid": "Guest", "signal": 42, "security": "open" } ] ``` - Error Response: `{ "status": "error", "message": "等待 WiFi 响应超时" }`、`{ "status": "error", "message": "WiFi 返回了无效 JSON: ..." }` ### POST /api/wifi/scan - Method: `POST` - Path: `/api/wifi/scan` - Request Body: 无 - Response Example: ```json [ { "ssid": "OfficeWiFi", "signal": 78, "security": "WPA2" } ] ``` - Error Response: 与 `GET /api/wifi/scan` 相同 ### POST /api/wifi/connect - Method: `POST` - Path: `/api/wifi/connect` - Request Body Example: ```json { "ssid": "OfficeWiFi", "password": "secret123" } ``` - Response Example: ```json { "status": "ok", "message": "WiFi 连接成功: OfficeWiFi" } ``` - Error Response: `{ "status": "error", "message": "等待 WiFi 响应超时" }`、`{ "status": "error", "message": "WiFi 操作失败" }` ### POST /api/wifi/ap/start - Method: `POST` - Path: `/api/wifi/ap/start` - Request Body Example: ```json { "ssid": "showen", "password": "12345678" } ``` - Response Example: ```json { "status": "ok", "message": "AP 热点已启动: SSID=showen" } ``` - Error Response: `{ "status": "error", "message": "JSON 格式错误: ..." }`、`{ "status": "error", "message": "等待 WiFi 响应超时" }` 说明:请求体可省略;默认 `ssid=showen`、`password=12345678`。 ### POST /api/wifi/hotspot/start - Method: `POST` - Path: `/api/wifi/hotspot/start` - Request Body Example: ```json { "ssid": "showen", "password": "12345678" } ``` - Response Example: ```json { "status": "ok", "message": "AP 热点已启动: SSID=showen" } ``` - Error Response: 与 `POST /api/wifi/ap/start` 相同 说明:这是 `POST /api/wifi/ap/start` 的兼容别名。 ### POST /api/wifi/ap/stop - Method: `POST` - Path: `/api/wifi/ap/stop` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "AP 热点已关闭" } ``` - Error Response: `{ "status": "error", "message": "等待 WiFi 响应超时" }`、`{ "status": "error", "message": "WiFi 操作失败" }` ### POST /api/wifi/hotspot/stop - Method: `POST` - Path: `/api/wifi/hotspot/stop` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "AP 热点已关闭" } ``` - Error Response: 与 `POST /api/wifi/ap/stop` 相同 说明:这是 `POST /api/wifi/ap/stop` 的兼容别名。 ## BLE ### POST /api/ble/start - Method: `POST` - Path: `/api/ble/start` - Request Body Example: ```json { "device_name": "Showen" } ``` - Response Example: ```json { "status": "ok", "message": "BLE 配网服务已内嵌运行中,设备名: Showen" } ``` - Error Response: `{ "status": "error", "message": "JSON 格式错误: ..." }` 说明:请求体可省略;未传时使用当前配置中的 `ble.device_name`。 ### POST /api/ble/stop - Method: `POST` - Path: `/api/ble/stop` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "BLE 配网服务随主进程运行,无需手动停止" } ``` - Error Response: 无业务级错误 JSON ### GET /api/ble/status - Method: `GET` - Path: `/api/ble/status` - Request Body: 无 - Response Example: ```json { "running": true, "embedded": true, "device_name": "Showen" } ``` - Error Response: `404/405` 由路由层处理;无业务级错误 JSON ## App 下载 ### GET /api/app/info - Method: `GET` - Path: `/api/app/info` - Request Body: 无 - Response Example: ```json { "version": "0.1.0", "apk_available": true, "apk_size": 18432000, "download_url": "/download/showen-app.apk" } ``` - Error Response: `404/405` 由路由层处理;无业务级错误 JSON ### GET /download/:filename - Method: `GET` - Path: `/download/:filename` - Request Body: 无 - Response Example: 二进制附件下载,响应头包含: ```text Content-Type: application/octet-stream Content-Disposition: attachment; filename="showen-app.apk" ``` - Error Response Example: ```text HTTP 400/404/500 text/html; charset=utf-8 无效的文件名 ``` 说明:该接口错误响应不是 JSON。 ## 插件管理 ### GET /api/plugins - Method: `GET` - Path: `/api/plugins` - Request Body: 无 - Response Example: ```json [ { "id": "wifi", "info": { "name": "WiFi Plugin", "version": "0.1.0", "description": "Manage WiFi via nmcli", "platform": "LinuxArm64" }, "is_dynamic": false, "error_policy": "auto_rollback", "error_count": 0, "max_errors": 5, "enabled": true, "test_results": [ { "capability": "wifi_scan", "passed": true, "message": "no test defined" } ], "capabilities": ["wifi_scan", "wifi_connect"], "needs_rollback": false } ] ``` - Error Response: `404/405` 由路由层处理;无业务级错误 JSON ### GET /api/plugins/:id - Method: `GET` - Path: `/api/plugins/:id` - Request Body: 无 - Response Example: ```json { "id": "wifi", "info": { "name": "WiFi Plugin", "version": "0.1.0", "description": "Manage WiFi via nmcli", "platform": "LinuxArm64" }, "is_dynamic": false, "error_policy": "auto_rollback", "error_count": 0, "max_errors": 5, "enabled": true, "test_results": [], "capabilities": ["wifi_scan", "wifi_connect"], "needs_rollback": false } ``` - Error Response: `{ "status": "error", "message": "plugin 'wifi' not found" }` ### POST /api/plugins/:id/enable - Method: `POST` - Path: `/api/plugins/:id/enable` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "plugin_enable 命令已发送" } ``` - Error Response: `{ "status": "error", "message": "发送失败: ..." }` ### POST /api/plugins/:id/disable - Method: `POST` - Path: `/api/plugins/:id/disable` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "plugin_disable 命令已发送" } ``` - Error Response: `{ "status": "error", "message": "发送失败: ..." }` ### POST /api/plugins/:id/rollback - Method: `POST` - Path: `/api/plugins/:id/rollback` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "plugin_rollback 命令已发送" } ``` - Error Response: `{ "status": "error", "message": "发送失败: ..." }` ### POST /api/plugins/:id/switch - Method: `POST` - Path: `/api/plugins/:id/switch` - Request Body Example: ```json { "version": "1.2.3" } ``` - Response Example: ```json { "status": "ok", "message": "版本切换请求已发送: wifi -> v1.2.3" } ``` - Error Response: `{ "status": "error", "message": "发送失败: ..." }` ### POST /api/plugins/install - Method: `POST` - Path: `/api/plugins/install` - Request Body Example: ```json { "id": "weather", "version": "0.3.0" } ``` - Response Example: ```json { "status": "ok", "message": "安装请求已发送: weather" } ``` - Error Response: `{ "status": "error", "message": "发送失败: ..." }` 说明:`version` 可省略,省略时请求体仍需提供 `id`。 ### POST /api/plugins/check-updates - Method: `POST` - Path: `/api/plugins/check-updates` - Request Body: 无 - Response Example: ```json { "status": "ok", "message": "plugin_check_updates 命令已发送" } ``` - Error Response: `{ "status": "error", "message": "发送失败: ..." }` ## 文件管理 目录参数 `:dir` 仅支持:`videos`、`configs`、`plugins`。 ### GET /api/files/:dir - Method: `GET` - Path: `/api/files/:dir?path=` - Request Body: 无 - Response Example: ```json [ { "name": "subdir", "is_dir": true, "size": 0 }, { "name": "intro.mp4", "is_dir": false, "size": 1048576 } ] ``` - Error Response: `{ "status": "error", "message": "不支持的目录: logs(仅支持 videos/configs/plugins)" }`、`{ "status": "error", "message": "路径不合法" }`、`{ "status": "error", "message": "目录不存在" }` ### POST /api/files/:dir/upload - Method: `POST` - Path: `/api/files/:dir/upload?path=` - Request Body Example: `multipart/form-data`,一个或多个 `file` 字段 - Response Example: ```json { "status": "ok", "message": "已上传 1 个文件: intro.mp4" } ``` - Error Response: `{ "status": "error", "message": "不支持的目录" }`、`{ "status": "error", "message": "目标目录不合法" }`、`{ "status": "error", "message": "未找到上传文件" }`、`{ "status": "error", "message": "文件大小超过限制: 单文件最大 100 MB" }` ### GET /api/files/:dir/download - Method: `GET` - Path: `/api/files/:dir/download?path=` - Request Body: 无 - Response Example: 二进制附件下载,响应头包含: ```text Content-Type: application/octet-stream Content-Disposition: attachment; filename="intro.mp4" ``` - Error Response Example: ```text HTTP 400/403/404 text/html; charset=utf-8 缺少 path 参数 ``` 说明:该接口错误响应不是 JSON。 ### POST /api/files/:dir/delete - Method: `POST` - Path: `/api/files/:dir/delete` - Request Body Example: ```json { "path": "subdir/intro.mp4" } ``` - Response Example: ```json { "status": "ok", "message": "已删除: subdir/intro.mp4" } ``` - Error Response: `{ "status": "error", "message": "不支持的目录" }`、`{ "status": "error", "message": "缺少 path" }`、`{ "status": "error", "message": "路径不合法" }`、`{ "status": "error", "message": "文件不存在" }` ### POST /api/files/move - Method: `POST` - Path: `/api/files/move` - Request Body Example: ```json { "from_dir": "videos", "from_path": "intro.mp4", "to_dir": "videos", "to_path": "archive/intro.mp4" } ``` - Response Example: ```json { "status": "ok", "message": "已移动: intro.mp4 → archive/intro.mp4" } ``` - Error Response: `{ "status": "error", "message": "源目录不支持" }`、`{ "status": "error", "message": "目标目录不支持" }`、`{ "status": "error", "message": "源路径不合法" }`、`{ "status": "error", "message": "目标路径已存在" }` ### POST /api/files/:dir/mkdir - Method: `POST` - Path: `/api/files/:dir/mkdir` - Request Body Example: ```json { "path": "archive" } ``` - Response Example: ```json { "status": "ok", "message": "已创建目录: archive" } ``` - Error Response: `{ "status": "error", "message": "不支持的目录" }`、`{ "status": "error", "message": "缺少 path" }`、`{ "status": "error", "message": "路径不合法" }`、`{ "status": "error", "message": "创建失败: ..." }` ## 已移除的旧文档端点 以下端点当前实现中不存在,不应再使用: - `/api/stop` - `/api/wifi/disconnect`