From d422ffd48e2ab789b2968a3db7f30e9519bc5c51 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Fri, 17 Jul 2026 11:08:47 +0800 Subject: [PATCH] refactor: rebrand to SafeSight Control (merge p0-dashboard) --- Readme.md | 38 +- cmd/{managerd => safesightd}/main.go | 26 +- docs/P0实施计划.md | 2 +- docs/产品化评估与规划.md | 8 +- docs/离线部署文档.md | 86 +-- go.mod | 2 +- internal/api/handlers.go | 6 +- internal/api/handlers_test.go | 24 +- internal/api/openapi.go | 550 +++++++++--------- internal/service/agent_client.go | 2 +- internal/service/config_assets.go | 4 +- internal/service/config_assets_test.go | 6 +- internal/service/config_preview.go | 118 ++-- internal/service/config_preview_test.go | 46 +- internal/service/discovery.go | 6 +- internal/service/model_management.go | 4 +- internal/service/model_management_test.go | 4 +- internal/service/registry.go | 4 +- internal/service/registry_test.go | 12 +- internal/service/resource_management.go | 4 +- internal/service/resource_management_test.go | 4 +- internal/service/standard_templates.go | 2 +- internal/service/task.go | 8 +- internal/service/task_test.go | 34 +- internal/service/template.go | 2 +- internal/service/template_test.go | 6 +- internal/storage/devices_repo.go | 2 +- internal/storage/devices_repo_test.go | 2 +- internal/storage/tasks_repo.go | 2 +- internal/storage/tasks_repo_test.go | 2 +- internal/web/ui.go | 8 +- internal/web/ui_test.go | 38 +- package.json | 4 +- managerd.json => safesightd.json | 0 scripts/deploy/build-offline-package.sh | 24 +- scripts/deploy/build-windows.ps1 | 74 +-- scripts/deploy/{3588admin => safesightd} | 82 +-- .../{3588admin.service => safesightd.service} | 8 +- scripts/dev-run.sh | 4 +- scripts/managerd.bat | 5 - scripts/safesightd.bat | 5 + scripts/{managerd.ps1 => safesightd.ps1} | 38 +- 42 files changed, 653 insertions(+), 653 deletions(-) rename cmd/{managerd => safesightd}/main.go (92%) rename managerd.json => safesightd.json (100%) rename scripts/deploy/{3588admin => safesightd} (90%) rename scripts/deploy/{3588admin.service => safesightd.service} (68%) delete mode 100644 scripts/managerd.bat create mode 100644 scripts/safesightd.bat rename scripts/{managerd.ps1 => safesightd.ps1} (81%) diff --git a/Readme.md b/Readme.md index d2198b5..7788355 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ -# managerd +# safesightd -`managerd` 是 RK3588 管理端后端服务,负责设备发现、设备注册表维护、代理访问设备端 `rk3588-agent`,并提供内嵌 Web UI、OpenAPI 页面和 HTTP API。 +`safesightd` 是 SafeSight Control 管理端后端服务,负责设备发现、设备注册表维护、代理访问设备端 `rk3588-agent`,并提供内嵌 Web UI、OpenAPI 页面和 HTTP API。 ## 当前状态 @@ -16,37 +16,37 @@ 默认通过单个可执行文件运行: ```bash -managerd +safesightd ``` 也可以指定配置文件路径: ```bash -managerd path/to/managerd.json +safesightd path/to/safesightd.json ``` 在当前仓库的 Windows 开发环境中,推荐使用统一脚本入口: ```bat -scripts\managerd.bat build -scripts\managerd.bat start -scripts\managerd.bat stop -scripts\managerd.bat restart -scripts\managerd.bat status +scripts\safesightd.bat build +scripts\safesightd.bat start +scripts\safesightd.bat stop +scripts\safesightd.bat restart +scripts\safesightd.bat status ``` 各动作说明: -- `build`: 编译 `.\cmd\managerd`,生成根目录下的 `managerd.exe` -- `start`: 启动当前仓库中的 `managerd.exe`,并检查 `/health` -- `stop`: 停止当前仓库对应的 `managerd.exe` +- `build`: 编译 `.\cmd\safesightd`,生成根目录下的 `safesightd.exe` +- `start`: 启动当前仓库中的 `safesightd.exe`,并检查 `/health` +- `stop`: 停止当前仓库对应的 `safesightd.exe` - `restart`: 先停止再启动 - `status`: 查看进程状态与健康检查结果 脚本实际入口文件: -- `scripts/managerd.bat` -- `scripts/managerd.ps1` +- `scripts/safesightd.bat` +- `scripts/safesightd.ps1` 程序启动后: @@ -192,7 +192,7 @@ Response: ### 设备代理接口 -以下接口由 managerd 转发到设备端 agent: +以下接口由 safesightd 转发到设备端 agent: - `GET /api/devices/{id}/info` -> `GET /v1/info` - `POST /api/devices/{id}/reload` -> `POST /v1/media-server/reload` @@ -233,7 +233,7 @@ Response: - `name`: 模型名 - `file`: 二进制文件 -行为:managerd 读取上传文件,并转发为设备端 agent 的 `PUT /v1/models/{name}`。 +行为:safesightd 读取上传文件,并转发为设备端 agent 的 `PUT /v1/models/{name}`。 ### Templates @@ -288,7 +288,7 @@ SSE 事件名为 `device_update`,数据格式: ## 配置文件 -`managerd.json` 示例: +`safesightd.json` 示例: ```json { @@ -303,7 +303,7 @@ SSE 事件名为 `device_update`,数据格式: 字段说明: -- `listen`: managerd 监听地址 +- `listen`: safesightd 监听地址 - `discovery_port`: 设备发现广播端口 - `discovery_timeout_ms`: 搜索超时 - `offline_after_ms`: 多久未更新则视为离线 @@ -312,7 +312,7 @@ SSE 事件名为 `device_update`,数据格式: ## 目录说明 -- `cmd/managerd`: 程序入口 +- `cmd/safesightd`: 程序入口 - `internal/api`: API 路由与处理器 - `internal/service`: discovery、registry、task、template、agent client - `internal/web`: 内嵌 Web UI diff --git a/cmd/managerd/main.go b/cmd/safesightd/main.go similarity index 92% rename from cmd/managerd/main.go rename to cmd/safesightd/main.go index 9cebf3e..9fad73e 100644 --- a/cmd/managerd/main.go +++ b/cmd/safesightd/main.go @@ -7,11 +7,11 @@ import ( "os" "path/filepath" - "3588AdminBackend/internal/api" - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/service" - "3588AdminBackend/internal/storage" - "3588AdminBackend/internal/web" + "safesight-control/internal/api" + "safesight-control/internal/config" + "safesight-control/internal/service" + "safesight-control/internal/storage" + "safesight-control/internal/web" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" @@ -19,10 +19,10 @@ import ( ) func main() { - cfgPath := "managerd.json" - if len(os.Args) > 1 { - cfgPath = os.Args[1] - } + cfgPath := "safesightd.json" + if len(os.Args) > 1 { + cfgPath = os.Args[1] + } cfg, err := config.LoadConfig(cfgPath) if err != nil { @@ -157,8 +157,8 @@ func main() { r.Post("/devices/{id}/models/upload", h.UploadModel) }) - fmt.Printf("Starting managerd on %s\n", cfg.Listen) - if err := http.ListenAndServe(cfg.Listen, r); err != nil { - log.Fatalf("failed to start server: %v", err) - } + fmt.Printf("Starting safesightd on %s\n", cfg.Listen) + if err := http.ListenAndServe(cfg.Listen, r); err != nil { + log.Fatalf("failed to start server: %v", err) + } } diff --git a/docs/P0实施计划.md b/docs/P0实施计划.md index 4ee21d5..a774c11 100644 --- a/docs/P0实施计划.md +++ b/docs/P0实施计划.md @@ -286,4 +286,4 @@ func (u *UI) pageDashboard(w http.ResponseWriter, r *http.Request) { | 后端 | `internal/web/ui/templates/monitor.html` | 新建:视频监控页面 | | 后端 | `internal/web/ui/templates/dashboard.html` | 修改:实时化改造 | | 后端 | `internal/web/ui.go` | 修改:新页面 handler + 路由 | -| 后端 | `cmd/managerd/main.go` | 修改:注入新服务 | +| 后端 | `cmd/safesightd/main.go` | 修改:注入新服务 | diff --git a/docs/产品化评估与规划.md b/docs/产品化评估与规划.md index 0aba49b..517e55b 100644 --- a/docs/产品化评估与规划.md +++ b/docs/产品化评估与规划.md @@ -1,7 +1,7 @@ # 产品化评估与后续规划 > 评估日期:2026-05-06 -> 范围:视觉识别服务(OrangePi3588Media)+ 管理后台(3588AdminBackend) +> 范围:视觉识别服务(OrangePi3588Media)+ 管理后台(SafeSight Control) --- @@ -75,7 +75,7 @@ 两个项目的架构基础扎实: - **media-server**:插件化 DAG 流水线,JSON 配置驱动,热更新/回滚,硬件解耦抽象清晰 -- **managerd**:分层架构(API→Service→Storage),RESTful,HTML/template 服务端渲染,无框架依赖 +- **safesightd**:分层架构(API→Service→Storage),RESTful,HTML/template 服务端渲染,无框架依赖 从产品化角度看,两边都有显著缺口,下面按优先级列出。 @@ -107,7 +107,7 @@ --- -## 三、管理后台(managerd) +## 三、管理后台(safesightd) ### ✅ 优势 @@ -249,7 +249,7 @@ | 项目 | 说明 | |------|------| -| `cmd/managerd` 目录名歧义 | 既是源码目录又被 gitignore 匹配为二进制 | +| `cmd/safesightd` 目录名歧义 | 既是源码目录又被 gitignore 匹配为二进制 | | 模板函数分散 | `modelTypeLabel`、`resourceTypeLabel` 等散落在 NewUI 中,应集中管理 | | agent 配置示例过时 | `agent.config.example.json` 路径与生产环境不一致 | | deploy.sh 交互选择 | 应支持完全无交互部署(CI/CD 友好) | diff --git a/docs/离线部署文档.md b/docs/离线部署文档.md index 70bdd59..a5c92d2 100644 --- a/docs/离线部署文档.md +++ b/docs/离线部署文档.md @@ -1,4 +1,4 @@ -# 3588AdminBackend 离线部署文档 +# SafeSight Control 离线部署文档 > **目标环境**: Ubuntu 22.04.5 LTS (离线环境,无法连接互联网) > **部署方式**: 在 Windows 上交叉编译,上传安装包到 Ubuntu 进行离线部署 @@ -21,7 +21,7 @@ ### 1.1 项目简介 -3588AdminBackend 是 Orange Pi 3588 媒体服务器的后台管理端,提供以下功能: +SafeSight Control 是 Orange Pi 3588 媒体服务器的后台管理端,提供以下功能: - 设备发现与注册管理 - 设备配置下发与批量任务管理 @@ -47,7 +47,7 @@ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ 1. 安装 Go 1.23+ │ │ │ │ 2. 运行 build-windows.ps1 │ │ -│ │ 3. 生成 3588AdminBackend-离线部署包-YYYYMMDD.tar.gz │ │ +│ │ 3. 生成 SafeSight Control-离线部署包-YYYYMMDD.tar.gz │ │ │ └──────────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────────┘ │ @@ -56,7 +56,7 @@ │ Ubuntu(生产环境) │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ 无需 Go 运行时!直接运行编译好的静态二进制文件 │ │ -│ │ - tar -xzf 3588AdminBackend-离线部署包-*.tar.gz │ │ +│ │ - tar -xzf SafeSight Control-离线部署包-*.tar.gz │ │ │ │ - sudo ./scripts/3588admin install │ │ │ │ - sudo ./scripts/3588admin start │ │ │ └──────────────────────────────────────────────────────────────┘ │ @@ -96,14 +96,14 @@ 将项目源码复制到 Windows 机器上,例如: ``` -C:\Users\YourName\3588AdminBackend\ +C:\Users\YourName\SafeSight Control\ ``` 目录结构应包含: ``` -3588AdminBackend/ +SafeSight Control/ ├── cmd/ -│ └── managerd/ +│ └── safesightd/ ├── internal/ ├── scripts/ │ └── deploy/ @@ -125,7 +125,7 @@ C:\Users\YourName\3588AdminBackend\ ```powershell # 进入项目目录 -cd C:\Users\YourName\3588AdminBackend\scripts\deploy +cd C:\Users\YourName\SafeSight Control\scripts\deploy # 执行构建脚本 .\build-windows.ps1 @@ -133,21 +133,21 @@ cd C:\Users\YourName\3588AdminBackend\scripts\deploy 或一行命令: ```powershell -& "C:YourName<3588AdminBackenddeployYourNamedeployYourName<3588AdminBackend -构建目录: C:YourName<3588AdminBackendYourNameYourNameYourName<3588AdminBackendYourNameYourName<3588AdminBackend +cd C:YourNamedeploy<3588admin build<3588admin-deploydeploy<3588admin.service build<3588admin-deployYourName<3588AdminBackend< +C:YourNameYourName<3588AdminBackend< ``` /opt/3588admin/ ├── bin/ -│ └── managerd # 主程序(Windows 交叉编译生成) +│ └── safesightd # 主程序(Windows 交叉编译生成) ├── config/ -│ └── managerd.json # 配置文件 +│ └── safesightd.json # 配置文件 ├── logs/ -│ └── managerd.log # 运行日志 +│ └── safesightd.log # 运行日志 ├── scripts/ │ ├── 3588admin # 统一管理脚本 │ └── 3588admin.service # 服务文件(复制用) @@ -555,7 +555,7 @@ sudo 3588admin stop sudo systemctl stop 3588admin # 2. 备份配置 -cp /opt/3588admin/config/managerd.json ~/managerd.json.bak +cp /opt/3588admin/config/safesightd.json ~/safesightd.json.bak # 3. 在 Windows 上重新构建新版本 # 运行 build-windows.ps1 @@ -589,4 +589,4 @@ echo "卸载完成" **文档版本**: 2.1 (Windows 构建版) **最后更新**: 2026-02-25 -**适用版本**: 3588AdminBackend V1.0+ +**适用版本**: SafeSight Control V1.0+ diff --git a/go.mod b/go.mod index 0516ad1..098f6c8 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module 3588AdminBackend +module safesight-control go 1.23.3 diff --git a/internal/api/handlers.go b/internal/api/handlers.go index 8321b88..ff1f97f 100644 --- a/internal/api/handlers.go +++ b/internal/api/handlers.go @@ -8,9 +8,9 @@ import ( "strings" "time" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/service" - "github.com/go-chi/chi/v5" + "safesight-control/internal/models" + "safesight-control/internal/service" + "github.com/go-chi/chi/v5" ) type Handler struct { diff --git a/internal/api/handlers_test.go b/internal/api/handlers_test.go index b4b3c4a..477ba15 100644 --- a/internal/api/handlers_test.go +++ b/internal/api/handlers_test.go @@ -1,18 +1,18 @@ package api import ( - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/service" - "bytes" - "encoding/json" - "net" - "net/http" - "net/http/httptest" - "strconv" - "strings" - "testing" - "time" + "safesight-control/internal/config" + "safesight-control/internal/models" + "safesight-control/internal/service" + "bytes" + "encoding/json" + "net" + "net/http" + "net/http/httptest" + "strconv" + "strings" + "testing" + "time" "github.com/go-chi/chi/v5" ) diff --git a/internal/api/openapi.go b/internal/api/openapi.go index f2b49de..6410e16 100644 --- a/internal/api/openapi.go +++ b/internal/api/openapi.go @@ -6,281 +6,281 @@ import ( ) func OpenAPI(w http.ResponseWriter, r *http.Request) { - spec := map[string]any{ - "openapi": "3.0.3", - "info": map[string]any{ - "title": "managerd API", - "version": "v1", - }, - "paths": map[string]any{ - "/health": map[string]any{ - "get": map[string]any{ - "responses": map[string]any{ - "200": map[string]any{ - "description": "ok", - "content": map[string]any{"text/plain": map[string]any{}}, - }, - }, - }, - }, - "/api/discovery/search": map[string]any{ - "post": map[string]any{ - "requestBody": map[string]any{ - "required": true, - "content": map[string]any{ - "application/json": map[string]any{ - "schema": map[string]any{ - "type": "object", - "properties": map[string]any{"timeout_ms": map[string]any{"type": "integer"}}, - }, - }, - }, - }, - "responses": map[string]any{ - "200": map[string]any{ - "description": "devices", - "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, - }, - }, - }, - }, - "/api/devices": map[string]any{ - "get": map[string]any{ - "responses": map[string]any{ - "200": map[string]any{ - "description": "devices", - "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, - }, - }, - }, - "post": map[string]any{ - "requestBody": map[string]any{ - "required": true, - "content": map[string]any{ - "application/json": map[string]any{ - "schema": map[string]any{ - "type": "object", - "properties": map[string]any{ - "device_id": map[string]any{"type": "string"}, - "device_name": map[string]any{"type": "string"}, - "ip": map[string]any{"type": "string"}, - "agent_port": map[string]any{"type": "integer"}, - "media_port": map[string]any{"type": "integer"}, - }, - "required": []any{"device_id", "ip"}, - }, - }, - }, - }, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "device", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/info": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "agent info", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/reload": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/rollback": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/media-server/start": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/media-server/restart": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/media-server/stop": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/media-server/status": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "status", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/graphs": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "graphs", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/graphs/{name}": map[string]any{ - "get": map[string]any{ - "parameters": []any{ - map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}, - map[string]any{"name": "name", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}, - }, - "responses": map[string]any{"200": map[string]any{"description": "graph", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/logs": map[string]any{ - "get": map[string]any{ - "parameters": []any{ - map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}, - map[string]any{"name": "limit", "in": "query", "required": false, "schema": map[string]any{"type": "integer"}}, - }, - "responses": map[string]any{"200": map[string]any{"description": "logs", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/config/apply": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "requestBody": map[string]any{ - "required": true, - "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, - }, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/models": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "models", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/models/upload": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "requestBody": map[string]any{ - "required": true, - "content": map[string]any{ - "multipart/form-data": map[string]any{ - "schema": map[string]any{ - "type": "object", - "properties": map[string]any{ - "name": map[string]any{"type": "string"}, - "file": map[string]any{"type": "string", "format": "binary"}, - }, - "required": []any{"name", "file"}, - }, - }, - }, - }, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/v1/config": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "config", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - "put": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "requestBody": map[string]any{ - "required": true, - "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, - }, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/v1/config/ui/schema": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "schema", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/v1/config/ui/state": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "state", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/v1/config/ui/plan": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "requestBody": map[string]any{ - "required": true, - "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, - }, - "responses": map[string]any{"200": map[string]any{"description": "plan", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/devices/{id}/v1/config/ui/apply": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "requestBody": map[string]any{ - "required": true, - "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, - }, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/v1/face-gallery": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "face gallery info", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - "put": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "requestBody": map[string]any{ - "required": true, - "content": map[string]any{"application/octet-stream": map[string]any{"schema": map[string]any{"type": "string", "format": "binary"}}}, - }, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/devices/{id}/v1/face-gallery/reload": map[string]any{ - "post": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "ok"}}, - }, - }, - "/api/templates": map[string]any{ - "get": map[string]any{ - "responses": map[string]any{"200": map[string]any{"description": "templates", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "array"}}}}}, - }, - }, - "/api/templates/{name}": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "name", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "template", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/tasks": map[string]any{ - "get": map[string]any{ - "responses": map[string]any{"200": map[string]any{"description": "tasks", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - "post": map[string]any{ - "requestBody": map[string]any{ - "required": true, - "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, - }, - "responses": map[string]any{"200": map[string]any{"description": "task_id", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, - }, - }, - "/api/tasks/{id}/events": map[string]any{ - "get": map[string]any{ - "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, - "responses": map[string]any{"200": map[string]any{"description": "SSE", "content": map[string]any{"text/event-stream": map[string]any{}}}}, - }, - }, - }, - } + spec := map[string]any{ + "openapi": "3.0.3", + "info": map[string]any{ + "title": "SafeSight Control API", + "version": "v1", + }, + "paths": map[string]any{ + "/health": map[string]any{ + "get": map[string]any{ + "responses": map[string]any{ + "200": map[string]any{ + "description": "ok", + "content": map[string]any{"text/plain": map[string]any{}}, + }, + }, + }, + }, + "/api/discovery/search": map[string]any{ + "post": map[string]any{ + "requestBody": map[string]any{ + "required": true, + "content": map[string]any{ + "application/json": map[string]any{ + "schema": map[string]any{ + "type": "object", + "properties": map[string]any{"timeout_ms": map[string]any{"type": "integer"}}, + }, + }, + }, + }, + "responses": map[string]any{ + "200": map[string]any{ + "description": "devices", + "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, + }, + }, + }, + }, + "/api/devices": map[string]any{ + "get": map[string]any{ + "responses": map[string]any{ + "200": map[string]any{ + "description": "devices", + "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, + }, + }, + }, + "post": map[string]any{ + "requestBody": map[string]any{ + "required": true, + "content": map[string]any{ + "application/json": map[string]any{ + "schema": map[string]any{ + "type": "object", + "properties": map[string]any{ + "device_id": map[string]any{"type": "string"}, + "device_name": map[string]any{"type": "string"}, + "ip": map[string]any{"type": "string"}, + "agent_port": map[string]any{"type": "integer"}, + "media_port": map[string]any{"type": "integer"}, + }, + "required": []any{"device_id", "ip"}, + }, + }, + }, + }, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "device", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/info": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "agent info", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/reload": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/rollback": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/media-server/start": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/media-server/restart": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/media-server/stop": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/media-server/status": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "status", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/graphs": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "graphs", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/graphs/{name}": map[string]any{ + "get": map[string]any{ + "parameters": []any{ + map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}, + map[string]any{"name": "name", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}, + }, + "responses": map[string]any{"200": map[string]any{"description": "graph", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/logs": map[string]any{ + "get": map[string]any{ + "parameters": []any{ + map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}, + map[string]any{"name": "limit", "in": "query", "required": false, "schema": map[string]any{"type": "integer"}}, + }, + "responses": map[string]any{"200": map[string]any{"description": "logs", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/config/apply": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "requestBody": map[string]any{ + "required": true, + "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, + }, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/models": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "models", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/models/upload": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "requestBody": map[string]any{ + "required": true, + "content": map[string]any{ + "multipart/form-data": map[string]any{ + "schema": map[string]any{ + "type": "object", + "properties": map[string]any{ + "name": map[string]any{"type": "string"}, + "file": map[string]any{"type": "string", "format": "binary"}, + }, + "required": []any{"name", "file"}, + }, + }, + }, + }, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/v1/config": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "config", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + "put": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "requestBody": map[string]any{ + "required": true, + "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, + }, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/v1/config/ui/schema": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "schema", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/v1/config/ui/state": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "state", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/v1/config/ui/plan": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "requestBody": map[string]any{ + "required": true, + "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, + }, + "responses": map[string]any{"200": map[string]any{"description": "plan", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/devices/{id}/v1/config/ui/apply": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "requestBody": map[string]any{ + "required": true, + "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, + }, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/v1/face-gallery": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "face gallery info", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + "put": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "requestBody": map[string]any{ + "required": true, + "content": map[string]any{"application/octet-stream": map[string]any{"schema": map[string]any{"type": "string", "format": "binary"}}}, + }, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/devices/{id}/v1/face-gallery/reload": map[string]any{ + "post": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "ok"}}, + }, + }, + "/api/templates": map[string]any{ + "get": map[string]any{ + "responses": map[string]any{"200": map[string]any{"description": "templates", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "array"}}}}}, + }, + }, + "/api/templates/{name}": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "name", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "template", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/tasks": map[string]any{ + "get": map[string]any{ + "responses": map[string]any{"200": map[string]any{"description": "tasks", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + "post": map[string]any{ + "requestBody": map[string]any{ + "required": true, + "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}, + }, + "responses": map[string]any{"200": map[string]any{"description": "task_id", "content": map[string]any{"application/json": map[string]any{"schema": map[string]any{"type": "object"}}}}}, + }, + }, + "/api/tasks/{id}/events": map[string]any{ + "get": map[string]any{ + "parameters": []any{map[string]any{"name": "id", "in": "path", "required": true, "schema": map[string]any{"type": "string"}}}, + "responses": map[string]any{"200": map[string]any{"description": "SSE", "content": map[string]any{"text/event-stream": map[string]any{}}}}, + }, + }, + }, + } w.Header().Set("Content-Type", "application/json; charset=utf-8") _ = json.NewEncoder(w).Encode(spec) diff --git a/internal/service/agent_client.go b/internal/service/agent_client.go index 28d4b58..8b3aa74 100644 --- a/internal/service/agent_client.go +++ b/internal/service/agent_client.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "3588AdminBackend/internal/config" + "safesight-control/internal/config" ) type AgentClient struct { diff --git a/internal/service/config_assets.go b/internal/service/config_assets.go index 34d4096..3946fa2 100644 --- a/internal/service/config_assets.go +++ b/internal/service/config_assets.go @@ -8,8 +8,8 @@ import ( "sort" "strings" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/storage" + "safesight-control/internal/models" + "safesight-control/internal/storage" ) var legacyBuiltinTemplateAliases = map[string]string{ diff --git a/internal/service/config_assets_test.go b/internal/service/config_assets_test.go index b69cdbc..05a2fcc 100644 --- a/internal/service/config_assets_test.go +++ b/internal/service/config_assets_test.go @@ -7,9 +7,9 @@ import ( "strings" "testing" - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/storage" + "safesight-control/internal/config" + "safesight-control/internal/models" + "safesight-control/internal/storage" ) func mustSaveTemplateRecord(t *testing.T, repo *storage.AssetsRepo, name string, description string, body string) { diff --git a/internal/service/config_preview.go b/internal/service/config_preview.go index 5703732..093ef8e 100644 --- a/internal/service/config_preview.go +++ b/internal/service/config_preview.go @@ -12,8 +12,8 @@ import ( "strings" "time" - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/storage" + "safesight-control/internal/config" + "safesight-control/internal/storage" ) var safeConfigName = regexp.MustCompile(`^[A-Za-z0-9_.-]+$`) @@ -251,56 +251,56 @@ func profileOverlayNames(raw map[string]any) []string { } func (s *ConfigPreviewService) renderFromAssets(req ConfigPreviewRequest, templateRaw map[string]any, templatePath string, profileRaw map[string]any, profilePath string, overlays []runtimeOverlayInput) (*ConfigPreviewResult, error) { - if err := validateConfigName(req.Template); err != nil { - return nil, fmt.Errorf("invalid template: %w", err) - } - if strings.TrimSpace(req.Profile) != "" { - if err := validateConfigName(req.Profile); err != nil { - return nil, fmt.Errorf("invalid profile: %w", err) - } - } - for _, overlay := range req.Overlays { - if err := validateConfigName(overlay); err != nil { - return nil, fmt.Errorf("invalid overlay %q: %w", overlay, err) - } - } - if req.ConfigID == "" { - req.ConfigID = "preview_" + time.Now().Format("20060102.150405") - } - if req.ConfigVersion == "" { - req.ConfigVersion = time.Now().Format("20060102.150405") - } - resolvedProfileRaw, err := s.resolveSceneBindings(profileRaw) - if err != nil { - return nil, err - } - metadata := map[string]any{ - "config_id": req.ConfigID, - "config_version": req.ConfigVersion, - "rendered_at": time.Now().Format(time.RFC3339), - "rendered_by": "managerd", - } - if strings.TrimSpace(req.DeviceID) != "" { - metadata["device_id"] = strings.TrimSpace(req.DeviceID) - } - doc, err := renderRuntimeConfig(templateRaw, templatePath, resolvedProfileRaw, profilePath, overlays, metadata) - if err != nil { - return nil, err - } - body, err := marshalConfigJSON(doc) - if err != nil { - return nil, err - } - renderedMetadata, _ := doc["metadata"].(map[string]any) - sum := sha256.Sum256(body) - return &ConfigPreviewResult{ - Request: req, - Root: previewRenderRoot(templatePath, profilePath), - Sha256: hex.EncodeToString(sum[:]), - Size: len(body), - Metadata: renderedMetadata, - JSON: string(body), - }, nil + if err := validateConfigName(req.Template); err != nil { + return nil, fmt.Errorf("invalid template: %w", err) + } + if strings.TrimSpace(req.Profile) != "" { + if err := validateConfigName(req.Profile); err != nil { + return nil, fmt.Errorf("invalid profile: %w", err) + } + } + for _, overlay := range req.Overlays { + if err := validateConfigName(overlay); err != nil { + return nil, fmt.Errorf("invalid overlay %q: %w", overlay, err) + } + } + if req.ConfigID == "" { + req.ConfigID = "preview_" + time.Now().Format("20060102.150405") + } + if req.ConfigVersion == "" { + req.ConfigVersion = time.Now().Format("20060102.150405") + } + resolvedProfileRaw, err := s.resolveSceneBindings(profileRaw) + if err != nil { + return nil, err + } + metadata := map[string]any{ + "config_id": req.ConfigID, + "config_version": req.ConfigVersion, + "rendered_at": time.Now().Format(time.RFC3339), + "rendered_by": "safesightd", + } + if strings.TrimSpace(req.DeviceID) != "" { + metadata["device_id"] = strings.TrimSpace(req.DeviceID) + } + doc, err := renderRuntimeConfig(templateRaw, templatePath, resolvedProfileRaw, profilePath, overlays, metadata) + if err != nil { + return nil, err + } + body, err := marshalConfigJSON(doc) + if err != nil { + return nil, err + } + renderedMetadata, _ := doc["metadata"].(map[string]any) + sum := sha256.Sum256(body) + return &ConfigPreviewResult{ + Request: req, + Root: previewRenderRoot(templatePath, profilePath), + Sha256: hex.EncodeToString(sum[:]), + Size: len(body), + Metadata: renderedMetadata, + JSON: string(body), + }, nil } func (s *ConfigPreviewService) resolveSceneBindings(raw map[string]any) (map[string]any, error) { @@ -427,13 +427,13 @@ func resolvedServiceBinding(asset *ConfigIntegrationServiceAsset) map[string]any } func previewRenderRoot(templatePath string, profilePath string) string { - if strings.HasPrefix(templatePath, "sqlite:") || strings.HasPrefix(profilePath, "sqlite:") { - return "SQLite" - } - if dir := filepath.Dir(templatePath); strings.TrimSpace(dir) != "" && dir != "." { - return dir - } - return "managerd" + if strings.HasPrefix(templatePath, "sqlite:") || strings.HasPrefix(profilePath, "sqlite:") { + return "SQLite" + } + if dir := filepath.Dir(templatePath); strings.TrimSpace(dir) != "" && dir != "." { + return dir + } + return "safesightd" } func writeResolvedConfigFile(pattern string, raw map[string]any) (string, error) { diff --git a/internal/service/config_preview_test.go b/internal/service/config_preview_test.go index 701de69..292c486 100644 --- a/internal/service/config_preview_test.go +++ b/internal/service/config_preview_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/storage" + "safesight-control/internal/config" + "safesight-control/internal/storage" ) func mustImportAssetsFromMediaRepo(t *testing.T, svc *ConfigPreviewService) { @@ -218,27 +218,27 @@ func TestConfigPreviewServiceRenderProfileEditorWritesResolvedBindings(t *testin t.Fatalf("RenderProfileEditor: %v", err) } - var doc map[string]any - if err := json.Unmarshal([]byte(result.JSON), &doc); err != nil { - t.Fatalf("unmarshal render result: %v", err) - } - templates, _ := doc["templates"].(map[string]any) - renderedTemplate, _ := templates["std_workshop_face_recognition_shoe_alarm__cam1"].(map[string]any) - nodes, _ := renderedTemplate["nodes"].([]any) - inputNode, _ := nodes[0].(map[string]any) - if got := stringValue(inputNode["url"]); got != "rtsp://10.0.0.1/live" { - t.Fatalf("expected expanded input url, got %#v", inputNode) - } - publishNode, _ := nodes[1].(map[string]any) - outputs, _ := publishNode["outputs"].([]any) - output, _ := outputs[0].(map[string]any) - if got := stringValue(output["path"]); got != "./web/hls/cam1/index.m3u8" { - t.Fatalf("expected expanded output path, got %#v", output) - } - metadata, _ := doc["metadata"].(map[string]any) - if got := stringValue(metadata["rendered_by"]); got != "managerd" { - t.Fatalf("expected managerd renderer metadata, got %#v", metadata) - } + var doc map[string]any + if err := json.Unmarshal([]byte(result.JSON), &doc); err != nil { + t.Fatalf("unmarshal render result: %v", err) + } + templates, _ := doc["templates"].(map[string]any) + renderedTemplate, _ := templates["std_workshop_face_recognition_shoe_alarm__cam1"].(map[string]any) + nodes, _ := renderedTemplate["nodes"].([]any) + inputNode, _ := nodes[0].(map[string]any) + if got := stringValue(inputNode["url"]); got != "rtsp://10.0.0.1/live" { + t.Fatalf("expected expanded input url, got %#v", inputNode) + } + publishNode, _ := nodes[1].(map[string]any) + outputs, _ := publishNode["outputs"].([]any) + output, _ := outputs[0].(map[string]any) + if got := stringValue(output["path"]); got != "./web/hls/cam1/index.m3u8" { + t.Fatalf("expected expanded output path, got %#v", output) + } + metadata, _ := doc["metadata"].(map[string]any) + if got := stringValue(metadata["rendered_by"]); got != "safesightd" { + t.Fatalf("expected safesightd renderer metadata, got %#v", metadata) + } } func TestConfigPreviewServiceRenderProfileEditorAllowsUnboundOptionalServiceSlot(t *testing.T) { diff --git a/internal/service/discovery.go b/internal/service/discovery.go index 40283d9..e491414 100644 --- a/internal/service/discovery.go +++ b/internal/service/discovery.go @@ -6,9 +6,9 @@ import ( "strings" "time" - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/models" - "github.com/google/uuid" + "safesight-control/internal/config" + "safesight-control/internal/models" + "github.com/google/uuid" ) const discoveryMagicV1 = "RK3588SYS_DISCOVERY_V1" diff --git a/internal/service/model_management.go b/internal/service/model_management.go index cce89b0..b62b56b 100644 --- a/internal/service/model_management.go +++ b/internal/service/model_management.go @@ -11,8 +11,8 @@ import ( "sort" "strings" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/storage" + "safesight-control/internal/models" + "safesight-control/internal/storage" ) type ModelManagementService struct { diff --git a/internal/service/model_management_test.go b/internal/service/model_management_test.go index 11b0f7d..4696ccb 100644 --- a/internal/service/model_management_test.go +++ b/internal/service/model_management_test.go @@ -5,8 +5,8 @@ import ( "path/filepath" "testing" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/storage" + "safesight-control/internal/models" + "safesight-control/internal/storage" ) func TestSyncStandardModelsFromDirectory(t *testing.T) { diff --git a/internal/service/registry.go b/internal/service/registry.go index c306ec9..25a39a5 100644 --- a/internal/service/registry.go +++ b/internal/service/registry.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/models" + "safesight-control/internal/config" + "safesight-control/internal/models" ) type RegistryService struct { diff --git a/internal/service/registry_test.go b/internal/service/registry_test.go index 05a5472..e29bf52 100644 --- a/internal/service/registry_test.go +++ b/internal/service/registry_test.go @@ -1,12 +1,12 @@ package service import ( - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/storage" - "path/filepath" - "testing" - "time" + "safesight-control/internal/config" + "safesight-control/internal/models" + "safesight-control/internal/storage" + "path/filepath" + "testing" + "time" ) func TestRegistryService_UpdateAndGet(t *testing.T) { diff --git a/internal/service/resource_management.go b/internal/service/resource_management.go index af1af25..647e898 100644 --- a/internal/service/resource_management.go +++ b/internal/service/resource_management.go @@ -10,8 +10,8 @@ import ( "sync" "time" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/storage" + "safesight-control/internal/models" + "safesight-control/internal/storage" ) type ResourceManagementService struct { diff --git a/internal/service/resource_management_test.go b/internal/service/resource_management_test.go index f18de0b..ea13679 100644 --- a/internal/service/resource_management_test.go +++ b/internal/service/resource_management_test.go @@ -5,8 +5,8 @@ import ( "path/filepath" "testing" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/storage" + "safesight-control/internal/models" + "safesight-control/internal/storage" ) func TestSyncStandardResourcesFromDirectory(t *testing.T) { diff --git a/internal/service/standard_templates.go b/internal/service/standard_templates.go index 77aa910..aa23691 100644 --- a/internal/service/standard_templates.go +++ b/internal/service/standard_templates.go @@ -7,7 +7,7 @@ import ( "path/filepath" "strings" - "3588AdminBackend/internal/storage" + "safesight-control/internal/storage" ) func ImportStandardTemplatesFromDir(repo *storage.AssetsRepo, dir string) (int, error) { diff --git a/internal/service/task.go b/internal/service/task.go index 38553a0..35a5932 100644 --- a/internal/service/task.go +++ b/internal/service/task.go @@ -10,10 +10,10 @@ import ( "strings" "sync" - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/storage" - "github.com/google/uuid" + "safesight-control/internal/config" + "safesight-control/internal/models" + "safesight-control/internal/storage" + "github.com/google/uuid" ) type TaskRepository interface { diff --git a/internal/service/task_test.go b/internal/service/task_test.go index 46b4363..05ec2d6 100644 --- a/internal/service/task_test.go +++ b/internal/service/task_test.go @@ -1,23 +1,23 @@ package service import ( - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/storage" - "crypto/sha256" - "encoding/hex" - "encoding/json" - "io" - "net" - "net/http" - "net/http/httptest" - "net/url" - "os" - "path/filepath" - "strconv" - "strings" - "testing" - "time" + "safesight-control/internal/config" + "safesight-control/internal/models" + "safesight-control/internal/storage" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "io" + "net" + "net/http" + "net/http/httptest" + "net/url" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" ) func waitForTaskDone(t *testing.T, task *models.Task, timeout time.Duration) models.TaskStatus { diff --git a/internal/service/template.go b/internal/service/template.go index fcb910e..cb9a2a5 100644 --- a/internal/service/template.go +++ b/internal/service/template.go @@ -5,7 +5,7 @@ import ( "os" "path/filepath" - "3588AdminBackend/internal/config" + "safesight-control/internal/config" ) type Template struct { diff --git a/internal/service/template_test.go b/internal/service/template_test.go index fba2a0a..fb96134 100644 --- a/internal/service/template_test.go +++ b/internal/service/template_test.go @@ -1,9 +1,9 @@ package service import ( - "3588AdminBackend/internal/config" - "os" - "testing" + "safesight-control/internal/config" + "os" + "testing" ) func TestTemplateService(t *testing.T) { diff --git a/internal/storage/devices_repo.go b/internal/storage/devices_repo.go index 3a003f7..23ac034 100644 --- a/internal/storage/devices_repo.go +++ b/internal/storage/devices_repo.go @@ -5,7 +5,7 @@ import ( "encoding/json" "time" - "3588AdminBackend/internal/models" + "safesight-control/internal/models" ) type DevicesRepo struct { diff --git a/internal/storage/devices_repo_test.go b/internal/storage/devices_repo_test.go index 0ed55a0..ae354f2 100644 --- a/internal/storage/devices_repo_test.go +++ b/internal/storage/devices_repo_test.go @@ -3,7 +3,7 @@ package storage import ( "testing" - "3588AdminBackend/internal/models" + "safesight-control/internal/models" ) func TestDevicesRepoUpsertsRuntimeSnapshot(t *testing.T) { diff --git a/internal/storage/tasks_repo.go b/internal/storage/tasks_repo.go index 63ed9be..3e5c881 100644 --- a/internal/storage/tasks_repo.go +++ b/internal/storage/tasks_repo.go @@ -5,7 +5,7 @@ import ( "encoding/json" "time" - "3588AdminBackend/internal/models" + "safesight-control/internal/models" ) type TasksRepo struct { diff --git a/internal/storage/tasks_repo_test.go b/internal/storage/tasks_repo_test.go index 97c8855..9e8cf65 100644 --- a/internal/storage/tasks_repo_test.go +++ b/internal/storage/tasks_repo_test.go @@ -4,7 +4,7 @@ import ( "path/filepath" "testing" - "3588AdminBackend/internal/models" + "safesight-control/internal/models" ) func openTestStore(t *testing.T) *Store { diff --git a/internal/web/ui.go b/internal/web/ui.go index d1abeb1..f046c50 100644 --- a/internal/web/ui.go +++ b/internal/web/ui.go @@ -18,10 +18,10 @@ import ( "strings" "time" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/service" - "3588AdminBackend/internal/storage" - "github.com/go-chi/chi/v5" + "safesight-control/internal/models" + "safesight-control/internal/service" + "safesight-control/internal/storage" + "github.com/go-chi/chi/v5" ) type UI struct { diff --git a/internal/web/ui_test.go b/internal/web/ui_test.go index 280ea9a..717ca56 100644 --- a/internal/web/ui_test.go +++ b/internal/web/ui_test.go @@ -1,25 +1,25 @@ package web import ( - "3588AdminBackend/internal/config" - "3588AdminBackend/internal/models" - "3588AdminBackend/internal/service" - "3588AdminBackend/internal/storage" - "bytes" - "context" - "encoding/json" - "fmt" - "mime/multipart" - "net" - "net/http" - "net/http/httptest" - "net/url" - "os" - "path/filepath" - "strconv" - "strings" - "testing" - "time" + "safesight-control/internal/config" + "safesight-control/internal/models" + "safesight-control/internal/service" + "safesight-control/internal/storage" + "bytes" + "context" + "encoding/json" + "fmt" + "mime/multipart" + "net" + "net/http" + "net/http/httptest" + "net/url" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" "github.com/go-chi/chi/v5" ) diff --git a/package.json b/package.json index ff6a3d7..465c5db 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "3588adminbackend", + "name": "safesight-control", "version": "1.0.0", "description": "`managerd` 是 RK3588 管理端后端服务,负责设备发现、设备注册表维护、代理访问设备端 `rk3588-agent`,并提供内嵌 Web UI、OpenAPI 页面和 HTTP API。", "main": "index.js", @@ -11,7 +11,7 @@ }, "repository": { "type": "git", - "url": "http://10.0.0.99:4000/Doni/3588AdminBackend.git" + "url": "http://10.0.0.99:4000/Doni/safesight-control.git" }, "keywords": [], "author": "", diff --git a/managerd.json b/safesightd.json similarity index 100% rename from managerd.json rename to safesightd.json diff --git a/scripts/deploy/build-offline-package.sh b/scripts/deploy/build-offline-package.sh index 1955340..127c3f4 100644 --- a/scripts/deploy/build-offline-package.sh +++ b/scripts/deploy/build-offline-package.sh @@ -50,24 +50,24 @@ echo "[3/7] 编译项目..." cd "$PROJECT_DIR" echo " 编译 Linux AMD64 版本..." -GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o "$PACKAGE_DIR/bin/managerd" ./cmd/managerd +GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o "$PACKAGE_DIR/bin/safesightd" ./cmd/safesightd echo " 验证编译结果..." -if [ ! -f "$PACKAGE_DIR/bin/managerd" ]; then +if [ ! -f "$PACKAGE_DIR/bin/safesightd" ]; then echo -e "${RED}错误: 编译失败${NC}" exit 1 fi -FILE_INFO=$(file "$PACKAGE_DIR/bin/managerd") +FILE_INFO=$(file "$PACKAGE_DIR/bin/safesightd") echo " $FILE_INFO" # 复制配置文件 echo "[4/7] 复制配置文件..." -if [ -f "$PROJECT_DIR/managerd.json" ]; then - cp "$PROJECT_DIR/managerd.json" "$PACKAGE_DIR/config/managerd.json.example" +if [ -f "$PROJECT_DIR/safesightd.json" ]; then + cp "$PROJECT_DIR/safesightd.json" "$PACKAGE_DIR/config/safesightd.json.example" else # 创建默认配置示例 - cat > "$PACKAGE_DIR/config/managerd.json.example" << 'EOF' + cat > "$PACKAGE_DIR/config/safesightd.json.example" << 'EOF' { "listen": "0.0.0.0:18080", "discovery_port": 35688, @@ -141,7 +141,7 @@ cat > "$PACKAGE_DIR/README-离线安装.txt" << 'EOF' sudo ./scripts/3588admin install /usr/local/3588admin 3. 修改配置 - sudo nano /opt/3588admin/config/managerd.json + sudo nano /opt/3588admin/config/safesightd.json 重点修改: - agent_token: 修改为安全的随机字符串 @@ -174,13 +174,13 @@ cat > "$PACKAGE_DIR/README-离线安装.txt" << 'EOF' 【文件位置】 安装目录: /opt/3588admin - 配置文件: /opt/3588admin/config/managerd.json - 日志文件: /opt/3588admin/logs/managerd.log + 配置文件: /opt/3588admin/config/safesightd.json + 日志文件: /opt/3588admin/logs/safesightd.log 【问题排查】 - 1. 查看日志: tail -f /opt/3588admin/logs/managerd.log - 2. 检查配置: python3 -m json.tool /opt/3588admin/config/managerd.json - 3. 检查端口: sudo netstat -tlnp | grep managerd + 1. 查看日志: tail -f /opt/3588admin/logs/safesightd.log + 2. 检查配置: python3 -m json.tool /opt/3588admin/config/safesightd.json + 3. 检查端口: sudo netstat -tlnp | grep safesightd 【防火墙】 sudo ufw allow 18080/tcp # HTTP API diff --git a/scripts/deploy/build-windows.ps1 b/scripts/deploy/build-windows.ps1 index 38fcb3a..222dc64 100644 --- a/scripts/deploy/build-windows.ps1 +++ b/scripts/deploy/build-windows.ps1 @@ -1,14 +1,14 @@ -# 3588AdminBackend Windows 构建脚本 +# SafeSight Control Windows 构建脚本 # 在 Windows 上交叉编译 Linux 版本并打包 # 配置 $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $ProjectDir = Split-Path -Parent (Split-Path -Parent $ScriptDir) $BuildDir = "$ProjectDir\build" -$PackageName = "3588AdminBackend-离线部署包-$(Get-Date -Format 'yyyyMMdd')" +$PackageName = "SafeSight Control-离线部署包-$(Get-Date -Format 'yyyyMMdd')" $PackageDir = "$BuildDir\$PackageName" -Write-Host "========== 3588AdminBackend Windows 构建 ==========" -ForegroundColor Green +Write-Host "========== SafeSight Control Windows 构建 ==========" -ForegroundColor Green Write-Host "项目目录: $ProjectDir" Write-Host "构建目录: $BuildDir" Write-Host "" @@ -45,9 +45,9 @@ $env:GOOS = "linux" $env:GOARCH = "amd64" $env:GOTOOLCHAIN = "local" -go build -ldflags="-s -w" -o "$PackageDir\bin\managerd" ./cmd/managerd +go build -ldflags="-s -w" -o "$PackageDir\bin\safesightd" ./cmd/safesightd -if ($LASTEXITCODE -ne 0 -or -not (Test-Path "$PackageDir\bin\managerd")) { +if ($LASTEXITCODE -ne 0 -or -not (Test-Path "$PackageDir\bin\safesightd")) { Write-Host "错误: 编译失败" -ForegroundColor Red exit 1 } @@ -56,8 +56,8 @@ Write-Host " 编译成功" -ForegroundColor Green # 复制配置文件 Write-Host "[4/6] 复制配置文件..." -if (Test-Path "$ProjectDir\managerd.json") { - Copy-Item "$ProjectDir\managerd.json" "$PackageDir\config\managerd.json.example" +if (Test-Path "$ProjectDir\safesightd.json") { + Copy-Item "$ProjectDir\safesightd.json" "$PackageDir\config\safesightd.json.example" } else { @" { @@ -68,7 +68,7 @@ if (Test-Path "$ProjectDir\managerd.json") { "agent_token": "CHANGE_ME", "concurrency": 5 } -"@ | Out-File -FilePath "$PackageDir\config\managerd.json.example" -Encoding UTF8 +"@ | Out-File -FilePath "$PackageDir\config\safesightd.json.example" -Encoding UTF8 } # 复制模板文件(如果有) @@ -79,17 +79,17 @@ if (Test-Path "$ProjectDir\templates") { # 复制脚本 Write-Host "[5/6] 复制部署脚本..." -Copy-Item "$ScriptDir\3588admin" "$PackageDir\scripts\" -Copy-Item "$ScriptDir\3588admin.service" "$PackageDir\systemd\" +Copy-Item "$ScriptDir\safesightd" "$PackageDir\scripts\" +Copy-Item "$ScriptDir\safesightd.service" "$PackageDir\systemd\" # 修复换行符为 LF(Unix 格式) -$scriptContent = Get-Content "$PackageDir\scripts\3588admin" -Raw +$scriptContent = Get-Content "$PackageDir\scripts\safesightd" -Raw $scriptContent = $scriptContent -replace "`r`n", "`n" -Set-Content -Path "$PackageDir\scripts\3588admin" -Value $scriptContent -NoNewLine +Set-Content -Path "$PackageDir\scripts\safesightd" -Value $scriptContent -NoNewLine -$serviceContent = Get-Content "$PackageDir\systemd\3588admin.service" -Raw +$serviceContent = Get-Content "$PackageDir\systemd\safesightd.service" -Raw $serviceContent = $serviceContent -replace "`r`n", "`n" -Set-Content -Path "$PackageDir\systemd\3588admin.service" -Value $serviceContent -NoNewLine +Set-Content -Path "$PackageDir\systemd\safesightd.service" -Value $serviceContent -NoNewLine # 复制文档 Write-Host "[6/6] 复制文档..." @@ -107,7 +107,7 @@ if (Test-Path "$ProjectDir\API_Device_RemoteMgmt_InterfaceTable.md") { # 创建版本信息 @" -3588AdminBackend 离线部署包 +SafeSight Control 离线部署包 版本: 1.0.0 构建时间: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') Go版本: $GoVersion @@ -118,7 +118,7 @@ Go版本: $GoVersion # 创建快速安装说明 @" ╔══════════════════════════════════════════════════════════════╗ -║ 3588AdminBackend 离线部署包 - 快速安装指南 ║ +║ SafeSight Control 离线部署包 - 快速安装指南 ║ ╚══════════════════════════════════════════════════════════════╝ 【系统要求】 @@ -141,44 +141,44 @@ Go版本: $GoVersion cd $PackageName/ 3. 执行安装 - sudo ./scripts/3588admin install + sudo ./scripts/safesightd install 4. 修改配置 - sudo nano /opt/3588admin/config/managerd.json + sudo nano /opt/safesightd/config/safesightd.json 重点修改: - agent_token: 修改为安全的随机字符串 - listen: 如需外部访问改为 "0.0.0.0:18080" 5. 启动服务 - sudo 3588admin start + sudo safesightd start 6. 验证安装 - sudo 3588admin status + sudo safesightd status 【常用命令】 - 3588admin start - 启动服务 - 3588admin stop - 停止服务 - 3588admin status - 查看状态 - 3588admin restart - 重启服务 - 3588admin upgrade - 升级服务 - 3588admin uninstall - 卸载服务 - 3588admin check - 检查环境 + safesightd start - 启动服务 + safesightd stop - 停止服务 + safesightd status - 查看状态 + safesightd restart - 重启服务 + safesightd upgrade - 升级服务 + safesightd uninstall - 卸载服务 + safesightd check - 检查环境 【快捷命令】 - 3588admin-start - 启动服务 - 3588admin-stop - 停止服务 - 3588admin-status - 查看状态 + safesightd-start - 启动服务 + safesightd-stop - 停止服务 + safesightd-status - 查看状态 【文件位置】 - 安装目录: /opt/3588admin - 配置文件: /opt/3588admin/config/managerd.json - 日志文件: /opt/3588admin/logs/managerd.log + 安装目录: /opt/safesightd + 配置文件: /opt/safesightd/config/safesightd.json + 日志文件: /opt/safesightd/logs/safesightd.log 【问题排查】 - 1. 查看日志: tail -f /opt/3588admin/logs/managerd.log - 2. 检查配置: python3 -m json.tool /opt/3588admin/config/managerd.json - 3. 检查端口: sudo netstat -tlnp | grep managerd + 1. 查看日志: tail -f /opt/safesightd/logs/safesightd.log + 2. 检查配置: python3 -m json.tool /opt/safesightd/config/safesightd.json + 3. 检查端口: sudo netstat -tlnp | grep safesightd 【防火墙】 sudo ufw allow 18080/tcp # HTTP API @@ -209,7 +209,7 @@ if ($LASTEXITCODE -eq 0 -and (Test-Path "$PackageName.tar.gz")) { Write-Host "" Write-Host "使用说明:" Write-Host "1. 将 $PackageName.tar.gz 上传到 Ubuntu 服务器" - Write-Host "2. 解压并运行: sudo ./scripts/3588admin install" + Write-Host "2. 解压并运行: sudo ./scripts/safesightd install" Write-Host "" } else { Write-Host "错误: 打包失败" -ForegroundColor Red diff --git a/scripts/deploy/3588admin b/scripts/deploy/safesightd similarity index 90% rename from scripts/deploy/3588admin rename to scripts/deploy/safesightd index e46743b..f9dfb61 100755 --- a/scripts/deploy/3588admin +++ b/scripts/deploy/safesightd @@ -1,5 +1,5 @@ #!/bin/bash -# 3588AdminBackend 统一管理脚本 +# SafeSight Control 统一管理脚本 # 提供安装、状态、升级、卸载等功能 set -e @@ -12,21 +12,21 @@ BLUE='\033[0;34m' NC='\033[0m' # 配置 -APP_NAME="managerd" +APP_NAME="safesightd" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -DEFAULT_INSTALL_DIR="/opt/3588admin" +DEFAULT_INSTALL_DIR="/opt/safesightd" INSTALL_DIR="${DEFAULT_INSTALL_DIR}" PID_FILE="$INSTALL_DIR/$APP_NAME.pid" # 显示帮助 cmd_help() { cat << EOF -3588AdminBackend 管理脚本 +SafeSight Control 管理脚本 用法: $0 <命令> [选项] 命令: - install [目录] 安装服务 (默认: /opt/3588admin) + install [目录] 安装服务 (默认: /opt/safesightd) status 查看服务状态 start 启动服务 stop 停止服务 @@ -69,7 +69,7 @@ get_install_dir() { # 环境检查 cmd_check() { - echo "========== 3588AdminBackend 环境检查 ==========" + echo "========== SafeSight Control 环境检查 ==========" echo "" PASS=0 @@ -233,7 +233,7 @@ cmd_install() { local CURRENT_DIR="$SCRIPT_DIR" local BASE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" - echo "========== 3588AdminBackend 离线安装 ==========" + echo "========== SafeSight Control 离线安装 ==========" echo "安装目录: $INSTALL_DIR" echo "" @@ -247,10 +247,10 @@ cmd_install() { exit 1 fi # 备份现有配置 - if [ -f "$INSTALL_DIR/config/managerd.json" ]; then - local BACKUP_FILE="$INSTALL_DIR/config/managerd.json.bak.$(date +%Y%m%d%H%M%S)" + if [ -f "$INSTALL_DIR/config/safesightd.json" ]; then + local BACKUP_FILE="$INSTALL_DIR/config/safesightd.json.bak.$(date +%Y%m%d%H%M%S)" echo "备份现有配置到: $BACKUP_FILE" - cp "$INSTALL_DIR/config/managerd.json" "$BACKUP_FILE" + cp "$INSTALL_DIR/config/safesightd.json" "$BACKUP_FILE" fi fi @@ -273,18 +273,18 @@ cmd_install() { echo " 复制二进制文件..." mkdir -p "$INSTALL_DIR/bin" - cp "$BASE_DIR/bin/managerd" "$INSTALL_DIR/bin/" 2>/dev/null || { - echo -e "${RED}错误: 未找到 managerd 二进制文件${NC}" + cp "$BASE_DIR/bin/safesightd" "$INSTALL_DIR/bin/" 2>/dev/null || { + echo -e "${RED}错误: 未找到 safesightd 二进制文件${NC}" echo "请确保在打包前已编译" exit 1 } echo " 复制配置文件..." mkdir -p "$INSTALL_DIR/config" - if [ -f "$BASE_DIR/config/managerd.json" ]; then - cp "$BASE_DIR/config/managerd.json" "$INSTALL_DIR/config/" - elif [ -f "$BASE_DIR/config/managerd.json.example" ]; then - cp "$BASE_DIR/config/managerd.json.example" "$INSTALL_DIR/config/" + if [ -f "$BASE_DIR/config/safesightd.json" ]; then + cp "$BASE_DIR/config/safesightd.json" "$INSTALL_DIR/config/" + elif [ -f "$BASE_DIR/config/safesightd.json.example" ]; then + cp "$BASE_DIR/config/safesightd.json.example" "$INSTALL_DIR/config/" fi # 复制模板文件 @@ -295,7 +295,7 @@ cmd_install() { # 3. 设置权限 echo "[3/5] 设置权限..." - chmod +x "$INSTALL_DIR/bin/managerd" + chmod +x "$INSTALL_DIR/bin/safesightd" mkdir -p "$INSTALL_DIR/logs" || { echo -e "${RED}错误: 无法创建日志目录 $INSTALL_DIR/logs${NC}" exit 1 @@ -307,8 +307,8 @@ cmd_install() { # 4. 初始化配置文件 echo "[4/5] 初始化配置文件..." - if [ ! -f "$INSTALL_DIR/config/managerd.json" ]; then - cat > "$INSTALL_DIR/config/managerd.json" << 'EOF' + if [ ! -f "$INSTALL_DIR/config/safesightd.json" ]; then + cat > "$INSTALL_DIR/config/safesightd.json" << 'EOF' { "listen": "0.0.0.0:18080", "discovery_port": 35688, @@ -319,7 +319,7 @@ cmd_install() { } EOF echo -e " ${GREEN}已创建默认配置文件${NC}" - echo -e " ${YELLOW}⚠️ 请编辑 $INSTALL_DIR/config/managerd.json 修改配置(特别是 agent_token)${NC}" + echo -e " ${YELLOW}⚠️ 请编辑 $INSTALL_DIR/config/safesightd.json 修改配置(特别是 agent_token)${NC}" else echo " 配置文件已存在,保留现有配置" fi @@ -340,7 +340,7 @@ EOF if [ -f "$CURRENT_DIR/3588admin.service" ]; then echo "[可选] 安装 Systemd 服务..." cp "$CURRENT_DIR/3588admin.service" /etc/systemd/system/ - sed -i "s|/opt/3588admin|$INSTALL_DIR|g" /etc/systemd/system/3588admin.service + sed -i "s|/opt/safesightd|$INSTALL_DIR|g" /etc/systemd/system/3588admin.service systemctl daemon-reload echo " 已安装 Systemd 服务" fi @@ -358,7 +358,7 @@ EOF echo " 3588admin uninstall - 卸载服务" echo "" echo -e "${YELLOW}重要提示:${NC}" - echo " 1. 请先编辑配置文件: $INSTALL_DIR/config/managerd.json" + echo " 1. 请先编辑配置文件: $INSTALL_DIR/config/safesightd.json" echo " 2. 务必修改 agent_token 为安全的随机字符串" echo "" echo -e "${YELLOW}防火墙配置:${NC}" @@ -373,10 +373,10 @@ cmd_start() { get_install_dir "$1" local BIN_PATH="$INSTALL_DIR/bin/$APP_NAME" - local CONFIG_PATH="$INSTALL_DIR/config/managerd.json" + local CONFIG_PATH="$INSTALL_DIR/config/safesightd.json" local LOG_DIR="$INSTALL_DIR/logs" - echo "========== 启动 3588AdminBackend ==========" + echo "========== 启动 SafeSight Control ==========" echo "应用目录: $INSTALL_DIR" echo "配置文件: $CONFIG_PATH" echo "" @@ -468,7 +468,7 @@ cmd_start() { cmd_stop() { get_install_dir "$1" - echo "========== 停止 3588AdminBackend ==========" + echo "========== 停止 SafeSight Control ==========" if [ -f "$PID_FILE" ]; then local PID=$(cat "$PID_FILE") @@ -528,10 +528,10 @@ cmd_status() { get_install_dir "$1" local BIN_PATH="$INSTALL_DIR/bin/$APP_NAME" - local CONFIG_PATH="$INSTALL_DIR/config/managerd.json" + local CONFIG_PATH="$INSTALL_DIR/config/safesightd.json" local LOG_DIR="$INSTALL_DIR/logs" - echo "========== 3588AdminBackend 状态 ==========" + echo "========== SafeSight Control 状态 ==========" echo "" echo "基本信息:" echo " 应用目录: $INSTALL_DIR" @@ -640,7 +640,7 @@ cmd_upgrade() { local SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" local BACKUP_DIR="/root/3588admin-backup-$(date +%Y%m%d%H%M%S)" - echo "========== 3588AdminBackend 升级 ==========" + echo "========== SafeSight Control 升级 ==========" echo "安装目录: $INSTALL_DIR" echo "备份目录: $BACKUP_DIR" echo "" @@ -653,7 +653,7 @@ cmd_upgrade() { fi # 确认 - read -p "确定要升级 3588AdminBackend? (y/N): " -n 1 -r + read -p "确定要升级 SafeSight Control? (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "升级已取消" @@ -669,8 +669,8 @@ cmd_upgrade() { echo "[2/5] 备份现有数据..." mkdir -p "$BACKUP_DIR" - if [ -f "$INSTALL_DIR/config/managerd.json" ]; then - cp "$INSTALL_DIR/config/managerd.json" "$BACKUP_DIR/" + if [ -f "$INSTALL_DIR/config/safesightd.json" ]; then + cp "$INSTALL_DIR/config/safesightd.json" "$BACKUP_DIR/" echo " 已备份配置文件" fi @@ -679,17 +679,17 @@ cmd_upgrade() { echo " 已备份日志文件" fi - if [ -f "$INSTALL_DIR/bin/managerd" ]; then - cp "$INSTALL_DIR/bin/managerd" "$BACKUP_DIR/managerd.old" + if [ -f "$INSTALL_DIR/bin/safesightd" ]; then + cp "$INSTALL_DIR/bin/safesightd" "$BACKUP_DIR/safesightd.old" echo " 已备份旧版本二进制" fi # 3. 更新二进制文件 echo "[3/5] 更新二进制文件..." local BASE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" - if [ -f "$BASE_DIR/bin/managerd" ]; then - cp "$BASE_DIR/bin/managerd" "$INSTALL_DIR/bin/managerd" - chmod +x "$INSTALL_DIR/bin/managerd" + if [ -f "$BASE_DIR/bin/safesightd" ]; then + cp "$BASE_DIR/bin/safesightd" "$INSTALL_DIR/bin/safesightd" + chmod +x "$INSTALL_DIR/bin/safesightd" echo -e " ${GREEN}已更新二进制文件${NC}" else echo -e "${YELLOW}警告: 未找到新的二进制文件${NC}" @@ -715,12 +715,12 @@ cmd_uninstall() { check_root get_install_dir "$1" - echo "========== 3588AdminBackend 卸载 ==========" + echo "========== SafeSight Control 卸载 ==========" echo "安装目录: $INSTALL_DIR" echo "" # 确认 - read -p "确定要完全卸载 3588AdminBackend? 此操作不可恢复! (y/N): " -n 1 -r + read -p "确定要完全卸载 SafeSight Control? 此操作不可恢复! (y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "卸载已取消" @@ -759,10 +759,10 @@ cmd_uninstall() { echo "[4/4] 删除安装文件..." local BACKUP_DIR="" if [ -d "$INSTALL_DIR" ]; then - if [ -f "$INSTALL_DIR/config/managerd.json" ]; then + if [ -f "$INSTALL_DIR/config/safesightd.json" ]; then BACKUP_DIR="/root/3588admin-backup-$(date +%Y%m%d%H%M%S)" mkdir -p "$BACKUP_DIR" - cp "$INSTALL_DIR/config/managerd.json" "$BACKUP_DIR/" + cp "$INSTALL_DIR/config/safesightd.json" "$BACKUP_DIR/" echo " 配置已备份到: $BACKUP_DIR/" fi @@ -773,7 +773,7 @@ cmd_uninstall() { echo "" echo -e "${GREEN}========== 卸载完成 ==========${NC}" if [ -n "$BACKUP_DIR" ]; then - echo "配置文件备份: $BACKUP_DIR/managerd.json" + echo "配置文件备份: $BACKUP_DIR/safesightd.json" fi } diff --git a/scripts/deploy/3588admin.service b/scripts/deploy/safesightd.service similarity index 68% rename from scripts/deploy/3588admin.service rename to scripts/deploy/safesightd.service index f997d68..d01cda9 100644 --- a/scripts/deploy/3588admin.service +++ b/scripts/deploy/safesightd.service @@ -1,6 +1,6 @@ [Unit] -Description=3588AdminBackend Service -Documentation=https://github.com/your-org/3588AdminBackend +Description=SafeSight Control Service +Documentation=https://github.com/your-org/SafeSight Control After=network.target network-online.target Wants=network-online.target @@ -8,8 +8,8 @@ Wants=network-online.target Type=simple User=root Group=root -WorkingDirectory=/opt/3588admin -ExecStart=/opt/3588admin/bin/managerd /opt/3588admin/config/managerd.json +WorkingDirectory=/opt/safesightd +ExecStart=/opt/safesightd/bin/safesightd /opt/safesightd/config/safesightd.json ExecReload=/bin/kill -HUP $MAINPID KillMode=process KillSignal=SIGTERM diff --git a/scripts/dev-run.sh b/scripts/dev-run.sh index 4ddbae9..648acc5 100644 --- a/scripts/dev-run.sh +++ b/scripts/dev-run.sh @@ -6,7 +6,7 @@ set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -CONFIG_FILE="$PROJECT_DIR/managerd.json" +CONFIG_FILE="$PROJECT_DIR/safesightd.json" echo "========== 3588AdminBackend 开发运行 ==========" echo "项目目录: $PROJECT_DIR" @@ -53,4 +53,4 @@ echo "按 Ctrl+C 停止服务" echo "" # 使用 go run 直接运行 -go run ./cmd/managerd -config "$CONFIG_FILE" +go run ./cmd/safesightd -config "$CONFIG_FILE" diff --git a/scripts/managerd.bat b/scripts/managerd.bat deleted file mode 100644 index d209830..0000000 --- a/scripts/managerd.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -setlocal -chcp 65001 >nul -pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0managerd.ps1" %* -exit /b %ERRORLEVEL% diff --git a/scripts/safesightd.bat b/scripts/safesightd.bat new file mode 100644 index 0000000..f8a31b4 --- /dev/null +++ b/scripts/safesightd.bat @@ -0,0 +1,5 @@ +@echo off +setlocal +chcp 65001 >nul +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0safesightd.ps1" %* +exit /b %ERRORLEVEL% diff --git a/scripts/managerd.ps1 b/scripts/safesightd.ps1 similarity index 81% rename from scripts/managerd.ps1 rename to scripts/safesightd.ps1 index 77c3479..b208e57 100644 --- a/scripts/managerd.ps1 +++ b/scripts/safesightd.ps1 @@ -7,18 +7,18 @@ $ErrorActionPreference = "Stop" $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $rootDir = (Resolve-Path (Join-Path $scriptDir "..")).Path -$exePath = Join-Path $rootDir "managerd.exe" -$configPath = Join-Path $rootDir "managerd.json" -$logPath = Join-Path $rootDir "managerd.local.log" -$errLogPath = Join-Path $rootDir "managerd.local.err.log" +$exePath = Join-Path $rootDir "safesightd.exe" +$configPath = Join-Path $rootDir "safesightd.json" +$logPath = Join-Path $rootDir "safesightd.local.log" +$errLogPath = Join-Path $rootDir "safesightd.local.err.log" function Write-Info { param([string]$Message) - Write-Host "[managerd] $Message" + Write-Host "[safesightd] $Message" } -function Get-ManagerdProcess { - return Get-Process -Name "managerd" -ErrorAction SilentlyContinue | Select-Object -First 1 +function Get-SafesightdProcess { + return Get-Process -Name "safesightd" -ErrorAction SilentlyContinue | Select-Object -First 1 } function Get-HealthInfo { @@ -64,7 +64,7 @@ function Wait-ForHealthOk { function Wait-ForStop { param([int]$Retries = 8) for ($i = 0; $i -lt $Retries; $i++) { - if (-not (Get-ManagerdProcess)) { + if (-not (Get-SafesightdProcess)) { return $true } Start-Sleep -Seconds 1 @@ -82,7 +82,7 @@ function Show-Health { } function Invoke-Build { - Write-Info "编译 managerd.exe ..." + Write-Info "编译 safesightd.exe ..." Push-Location $rootDir try { & go build -o $exePath .\cmd\managerd @@ -97,17 +97,17 @@ function Invoke-Build { function Invoke-Start { if (-not (Test-Path $exePath)) { - throw "未找到 managerd.exe,请先执行 build" + throw "未找到 safesightd.exe,请先执行 build" } - $proc = Get-ManagerdProcess + $proc = Get-SafesightdProcess if ($proc) { Write-Info ("已在运行,PID={0}" -f $proc.Id) Show-Health return } - Write-Info "启动 managerd.exe ..." + Write-Info "启动 safesightd.exe ..." Start-Process -FilePath $exePath ` -ArgumentList $configPath ` -WorkingDirectory $rootDir ` @@ -116,7 +116,7 @@ function Invoke-Start { -WindowStyle Hidden $null = Wait-ForHealthOk - $proc = Get-ManagerdProcess + $proc = Get-SafesightdProcess if (-not $proc) { throw "进程未启动成功" } @@ -126,13 +126,13 @@ function Invoke-Start { } function Invoke-Stop { - $proc = Get-ManagerdProcess + $proc = Get-SafesightdProcess if (-not $proc) { Write-Info "当前未运行" return } - Write-Info ("停止 managerd.exe,PID={0} ..." -f $proc.Id) + Write-Info ("停止 safesightd.exe,PID={0} ..." -f $proc.Id) Stop-Process -Id $proc.Id -Force if (-not (Wait-ForStop)) { throw "进程停止超时" @@ -146,7 +146,7 @@ function Invoke-Restart { } function Show-Status { - $proc = Get-ManagerdProcess + $proc = Get-SafesightdProcess if ($proc) { Write-Info ("进程状态: running (PID={0})" -f $proc.Id) } else { @@ -166,9 +166,9 @@ function Show-Usage { " managerd.bat help" "" "说明:" - " build 编译 .\cmd\managerd 到 managerd.exe" - " start 启动现有 managerd.exe,并做健康检查" - " stop 停止当前仓库对应的 managerd.exe" + " build 编译 .\cmd\managerd 到 safesightd.exe" + " start 启动现有 safesightd.exe,并做健康检查" + " stop 停止当前仓库对应的 safesightd.exe" " restart 先 stop 再 start" " status 查看进程状态与 /health" " help 显示帮助"