# managerd `managerd` 是 RK3588 管理端后端服务,负责设备发现、设备注册表维护、代理访问设备端 `rk3588-agent`,并提供内嵌 Web UI、OpenAPI 页面和 HTTP API。 ## 当前状态 - 提供 HTTP API,供前端或其他本地工具调用。 - 内嵌 Web UI,启动后可直接在浏览器访问。 - 支持 UDP 广播发现设备,并维护内存中的设备在线状态。 - 支持代理访问设备端 agent 的常用接口,以及 `/v1/*` 通用透传。 - 支持批量任务执行,并通过 SSE 推送逐设备状态。 - 模板从本地 `templates/*.json` 读取。 ## 运行方式 默认通过单个可执行文件运行: ```bash managerd ``` 也可以指定配置文件路径: ```bash managerd path/to/managerd.json ``` 在当前仓库的 Windows 开发环境中,推荐使用统一脚本入口: ```bat scripts\managerd.bat build scripts\managerd.bat start scripts\managerd.bat stop scripts\managerd.bat restart scripts\managerd.bat status ``` 各动作说明: - `build`: 编译 `.\cmd\managerd`,生成根目录下的 `managerd.exe` - `start`: 启动当前仓库中的 `managerd.exe`,并检查 `/health` - `stop`: 停止当前仓库对应的 `managerd.exe` - `restart`: 先停止再启动 - `status`: 查看进程状态与健康检查结果 脚本实际入口文件: - `scripts/managerd.bat` - `scripts/managerd.ps1` 程序启动后: - `GET /` 会重定向到 `/ui` - `GET /ui` 为内嵌管理页面 - `GET /openapi.json` 返回 OpenAPI 描述 - `GET /health` 返回健康检查结果 当前仓库中的示例配置监听地址为 `0.0.0.0:18080`。 ## 依赖 - Go `1.23.3` - `github.com/go-chi/chi/v5` - `github.com/go-chi/cors` - `github.com/google/uuid` ## 主要模块 ### Discovery - 向所有可用广播网卡发送 UDP discover 请求 - 在本地临时 UDP 端口监听回复 - 按 `device_id` 去重,并使用最新回复更新注册表 ### Device Registry - 以内存维护设备列表 - 每 2 秒执行一次离线判定 - 超过 `offline_after_ms` 未更新则标记为离线 - 每 30 秒对在线设备拉取一次 `GET /v1/graphs`,更新 `graphs` 字段 - 除 UDP 发现外,成功代理调用设备接口时也会刷新设备 `last_seen_ms` ### Agent Client - 默认 HTTP 请求超时为 3 秒 - 对配置下发、模型上传、`/v1/config/ui/*`、人脸库上传等长操作使用 120 秒超时 - 自动附带全局 `X-RK-Token` ### Template Service - 从本地 `templates/` 目录加载 `.json` 模板 - 返回模板列表和单个模板详情 - 当前没有实现 embed 模板加载 ### Task Runner - 支持并发执行,默认并发数为 `concurrency` - 支持 SSE 推送逐设备状态 - 当前支持的任务类型: - `config_apply` - `reload` - `rollback` - `media_start` - `media_restart` - `media_stop` ## API 概览 ### 基础接口 - `GET /health` - `GET /openapi.json` - `GET /` -> 302 跳转到 `/ui` - `GET /ui` ### Discovery #### `POST /api/discovery/search` Request: ```json { "timeout_ms": 1200 } ``` Response: ```json { "items": [ { "device_id": "...", "hostname": "...", "ip": "...", "agent_port": 9100, "media_port": 9000, "device_name": "...", "version": "...", "git_sha": "...", "uptime_sec": 0, "last_seen_ms": 0, "online": true } ] } ``` ### Devices #### `GET /api/devices` 返回当前注册表中的设备列表: ```json { "items": [ { "device_id": "...", "hostname": "...", "ip": "...", "agent_port": 9100, "media_port": 9000, "device_name": "...", "version": "...", "git_sha": "...", "uptime_sec": 0, "last_seen_ms": 0, "online": true, "graphs": {} } ] } ``` #### `POST /api/devices` 手工添加一个设备到注册表: ```json { "device_id": "demo-device", "device_name": "Demo", "ip": "192.168.1.10", "agent_port": 9100, "media_port": 9000 } ``` #### `GET /api/devices/{id}` 直接返回该设备对象。 ### 设备代理接口 以下接口由 managerd 转发到设备端 agent: - `GET /api/devices/{id}/info` -> `GET /v1/info` - `POST /api/devices/{id}/reload` -> `POST /v1/media-server/reload` - `POST /api/devices/{id}/rollback` -> `POST /v1/media-server/rollback` - `GET /api/devices/{id}/graphs` -> `GET /v1/graphs` - `GET /api/devices/{id}/graphs/{name}` -> `GET /v1/graphs/{name}` - `GET /api/devices/{id}/logs?limit=200` -> `GET /v1/logs/recent?limit=200` - `POST /api/devices/{id}/config/apply` -> `PUT /v1/config` - `GET /api/devices/{id}/models` -> `GET /v1/models` - `POST /api/devices/{id}/media-server/start` -> `POST /v1/media-server/start` - `POST /api/devices/{id}/media-server/restart` -> `POST /v1/media-server/restart` - `POST /api/devices/{id}/media-server/stop` -> `POST /v1/media-server/stop` - `GET /api/devices/{id}/media-server/status` -> `GET /v1/media-server/status` #### 通用透传 - `ANY /api/devices/{id}/v1/*` 该路由会将 `/api/devices/{id}` 之后的路径原样透传到设备端 agent,可用于: - `/v1/config` - `/v1/config/ui/schema` - `/v1/config/ui/state` - `/v1/config/ui/plan` - `/v1/config/ui/apply` - `/v1/face-gallery` - `/v1/face-gallery/reload` - 以及其他已存在的 `/v1/*` 接口 ### 模型上传 #### `POST /api/devices/{id}/models/upload` 请求类型:`multipart/form-data` 字段: - `name`: 模型名 - `file`: 二进制文件 行为:managerd 读取上传文件,并转发为设备端 agent 的 `PUT /v1/models/{name}`。 ### Templates - `GET /api/templates` - `GET /api/templates/{name}` 当前模板数据来自本地 `templates/*.json`。 ### Tasks #### `POST /api/tasks` Request: ```json { "type": "config_apply", "device_ids": ["device-a", "device-b"], "payload": { "config": {} } } ``` 说明: - `config_apply` 会将 payload 作为配置内容下发到 `/v1/config` - `media_start` 和 `media_restart` 可选接收 `{"config":"xxx"}` 形式的 payload Response: ```json { "task_id": "..." } ``` #### `GET /api/tasks` 返回当前内存中的任务列表。 #### `GET /api/tasks/{id}/events` SSE 事件名为 `device_update`,数据格式: ```json { "device_id": "...", "status": "running", "progress": 0.0, "error": "" } ``` ## 配置文件 `managerd.json` 示例: ```json { "listen": "0.0.0.0:18080", "discovery_port": 35688, "discovery_timeout_ms": 1200, "offline_after_ms": 10000, "agent_token": "CHANGE_ME", "concurrency": 5 } ``` 字段说明: - `listen`: managerd 监听地址 - `discovery_port`: 设备发现广播端口 - `discovery_timeout_ms`: 搜索超时 - `offline_after_ms`: 多久未更新则视为离线 - `agent_token`: 转发到设备端 agent 的统一 token - `concurrency`: 批量任务并发数 ## 目录说明 - `cmd/managerd`: 程序入口 - `internal/api`: API 路由与处理器 - `internal/service`: discovery、registry、task、template、agent client - `internal/web`: 内嵌 Web UI - `templates`: 本地模板 - `scripts/deploy`: 部署脚本 ## 验证现状 当前仓库已通过: ```bash go test ./... ```