372 lines
10 KiB
Markdown
372 lines
10 KiB
Markdown
# 设备端远程管理接口清单表(V1:对外 rk3588-agent;对内 media-server)
|
||
|
||
> 目标:供管理端(Go)与设备端联调对照。
|
||
>
|
||
> 约定:
|
||
> - 对外:`rk3588-agent` HTTP 端口默认 `9100`(可配置),UDP 发现端口默认 `35688`。
|
||
> - 对内:`media-server` 继续提供现有 `/api/*`(默认 9000),由 agent 本机调用。
|
||
|
||
---
|
||
|
||
## 0. 通用规范
|
||
|
||
### 0.1 基础 URL
|
||
- Agent Base: `http://<device_ip>:<agent_port>`
|
||
- Media-server Base(仅 agent 使用): `http://127.0.0.1:<media_port>`
|
||
|
||
### 0.2 鉴权(agent 对外)
|
||
- Header:`X-RK-Token: <token>`
|
||
- **必须鉴权**:所有写接口(PUT/POST 会改变设备状态或写盘)
|
||
- **读接口**:默认可不鉴权;若 `agent.require_token_for_read=true` 则也必须鉴权
|
||
|
||
### 0.3 统一响应格式
|
||
- 成功(通用):`{"ok":true}`
|
||
- 失败(通用):`{"error":"<message>"}`(与现有 `ErrorJson()` 风格一致)
|
||
|
||
### 0.4 统一错误码/HTTP 状态(agent 对外)
|
||
agent 不要求返回结构化 error_code(保持 `{"error":...}`),但**要求 HTTP 状态码语义稳定**:
|
||
|
||
| 场景 | HTTP | error.message 示例 |
|
||
|---|---:|---|
|
||
| 未鉴权/Token 错误/缺失 | 401 | `unauthorized` |
|
||
| JSON 解析失败 / 字段缺失 / 校验失败 | 400 | `invalid json: ...` / `validation failed: ...` |
|
||
| 资源不存在 | 404 | `not found` |
|
||
| 方法不允许 | 405 | `method not allowed` |
|
||
| 冲突(如 node_id 不唯一等) | 409 | `... not unique ...` |
|
||
| 写盘失败/内部异常/reload 崩溃性失败 | 500 | `internal error: ...` |
|
||
| 上传过大 | 413(推荐)或 400 | `payload too large` |
|
||
|
||
### 0.5 端口与协议
|
||
- UDP 发现:`35688/udp`(可配置)
|
||
- Agent HTTP:`9100/tcp`(默认,可配置)
|
||
- Media-server HTTP:`9000/tcp`(默认,可配置)
|
||
|
||
---
|
||
|
||
## 1. UDP 发现协议(Option A)
|
||
|
||
### 1.1 Discover 请求(manager → broadcast)
|
||
**发送目标**:同网段广播地址 `255.255.255.255:35688` 或各网卡广播地址
|
||
|
||
**数据格式**:两行 UTF-8 文本
|
||
|
||
Line1(固定魔法串):
|
||
```
|
||
RK3588SYS_DISCOVERY_V1
|
||
```
|
||
|
||
Line2(JSON):
|
||
```json
|
||
{"type":"discover","req_id":"<uuid>","reply_port":0}
|
||
```
|
||
|
||
字段:
|
||
- `type`: 固定 `discover`
|
||
- `req_id`: 管理端生成 UUID,用于匹配回复
|
||
- `reply_port`: 保留字段(V1 可固定 0)
|
||
|
||
### 1.2 Discover 回复(device → manager 单播)
|
||
**发送目标**:请求报文 source ip:source port
|
||
|
||
两行文本:
|
||
|
||
Line1:
|
||
```
|
||
RK3588SYS_DISCOVERY_V1
|
||
```
|
||
|
||
Line2(JSON):
|
||
```json
|
||
{
|
||
"type":"discover_reply",
|
||
"req_id":"<uuid>",
|
||
"device_id":"rk3588-...",
|
||
"device_name":"rk3588-cam-01",
|
||
"hostname":"rk3588",
|
||
"ip":"10.0.0.21",
|
||
"agent_port":9100,
|
||
"media_port":9000,
|
||
"version":"0.0.0-dev",
|
||
"git_sha":"e5894c2",
|
||
"uptime_sec":12345
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
- `device_id`: 稳定唯一(优先 `/etc/machine-id`,否则 MAC/序列号;最后 fallback 生成并落盘)
|
||
- `device_name`: 可配置的人类可读名称(agent 配置 `device_name`)
|
||
- `agent_port`: agent HTTP 端口
|
||
- `media_port`: media-server HTTP 端口(用于调试/展示;管理端可不直连)
|
||
|
||
---
|
||
|
||
## 2. 设备信息(agent 对外)
|
||
|
||
### 2.1 `GET /v1/info`
|
||
用途:设备列表/详情页展示、联调确认端口/版本/配置路径。
|
||
|
||
**Auth**:读接口(见 0.2)
|
||
|
||
Response 200:
|
||
```json
|
||
{
|
||
"device_id":"rk3588-...",
|
||
"device_name":"rk3588-cam-01",
|
||
"hostname":"rk3588",
|
||
"ip":"10.0.0.21",
|
||
"agent_port":9100,
|
||
"media_port":9000,
|
||
"version":"0.0.0-dev",
|
||
"git_sha":"e5894c2",
|
||
"config_path":"/etc/rk3588sys/config.json",
|
||
"last_good_path":"/etc/rk3588sys/config.json.last_good.json",
|
||
"uptime_sec":12345
|
||
}
|
||
```
|
||
|
||
失败:401/500 + `{"error":"..."}`
|
||
|
||
---
|
||
|
||
## 3. 配置下发(agent 对外)
|
||
|
||
### 3.1 `PUT /v1/config`
|
||
用途:管理端上传完整 root config(可含 templates/instances),agent 原子写盘后触发 `media-server` reload。
|
||
|
||
**Auth**:必须(401)
|
||
|
||
Headers:
|
||
- `Content-Type: application/json`
|
||
- `X-RK-Token: ...`
|
||
|
||
Body:root config JSON
|
||
|
||
agent 处理步骤(必须满足):
|
||
1) 解析 JSON(语法有效即可;语义校验交由 media-server reload)
|
||
2) 原子写入 `config_path`
|
||
3) 调用 media-server:`POST /api/config/reload`
|
||
4) 若 reload 失败:调用 media-server:`POST /api/config/rollback`,并返回 500(包含 reload/rollback 错误信息)
|
||
|
||
Response 200:
|
||
```json
|
||
{"ok":true}
|
||
```
|
||
|
||
失败:
|
||
- 400:JSON 解析失败
|
||
- 500:写盘失败 / reload 失败(已尝试 rollback)
|
||
|
||
---
|
||
|
||
## 4. 模型管理(agent 对外)
|
||
|
||
### 4.1 `PUT /v1/models/{name}`
|
||
用途:上传模型文件并落盘,维护 manifest,返回可引用的 `path`。
|
||
|
||
**Auth**:必须(401)
|
||
|
||
Path params:
|
||
- `name`: string(建议仅允许 `[A-Za-z0-9._-]`,超出则 400)
|
||
|
||
Headers:
|
||
- `Content-Type: application/octet-stream`
|
||
- `Content-Length: <n>`(必须)
|
||
- `X-RK-Token: ...`
|
||
- `X-Model-Sha256: <hex>`(可选;若存在必须匹配实际 sha256,否则 400)
|
||
|
||
Body:二进制文件(建议限制扩展名白名单 `.rknn`;V1 可由 name 或内容类型控制)
|
||
|
||
Response 200:
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"name": "yolov5s-640",
|
||
"sha256": "...",
|
||
"path": "/opt/rk3588sys/models/files/yolov5s-640__abcd.rknn",
|
||
"size": 12345678
|
||
}
|
||
```
|
||
|
||
失败:
|
||
- 400:缺 Content-Length / name 非法 / sha256 不匹配
|
||
- 413(推荐)或 400:超过 `max_upload_mb`
|
||
- 500:写盘失败/manifest 更新失败
|
||
|
||
### 4.2 `GET /v1/models`
|
||
用途:列出设备端已有模型。
|
||
|
||
**Auth**:读接口(见 0.2)
|
||
|
||
Response 200:
|
||
```json
|
||
{
|
||
"items": [
|
||
{
|
||
"name": "yolov5s-640",
|
||
"sha256": "...",
|
||
"path": "/opt/rk3588sys/models/files/...",
|
||
"size": 123,
|
||
"mtime_ms": 1730000000000
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
失败:500 + `{"error":"..."}`
|
||
|
||
---
|
||
|
||
## 5. 业务图热更新/回滚(agent 对外)
|
||
|
||
### 5.1 `POST /v1/media-server/reload`
|
||
用途:触发本机 media-server `POST /api/config/reload`。
|
||
|
||
**Auth**:必须(401)
|
||
|
||
Response 200:`{"ok":true}`
|
||
|
||
失败:500 + `{"error":"..."}`
|
||
|
||
### 5.2 `POST /v1/media-server/rollback`
|
||
用途:触发本机 media-server `POST /api/config/rollback`。
|
||
|
||
**Auth**:必须(401)
|
||
|
||
Response 200:`{"ok":true}`
|
||
|
||
失败:500 + `{"error":"..."}`
|
||
|
||
### 5.3 `PUT /v1/media-server/configs/{name}`
|
||
用途:上传 media-server 配置文件到 `agent.media_server_process.configs_dir`。
|
||
|
||
批量上传:对不同文件名重复调用该接口即可。
|
||
|
||
**Auth**:必须(401)
|
||
|
||
Headers:
|
||
- `Content-Type: application/json`
|
||
- `X-RK-Token: ...`
|
||
|
||
Path params:
|
||
- `name`: string(仅允许 `[A-Za-z0-9._-]`,禁止 `/`、`\\`、`..`;若无 `.json` 后缀则自动追加)
|
||
|
||
Body:media-server 配置 JSON
|
||
|
||
Response 200:
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"name": "cam1.json",
|
||
"path": "/opt/rk3588sys/configs/cam1.json",
|
||
"size": 1234,
|
||
"mtime_ms": 1730000000000
|
||
}
|
||
```
|
||
|
||
失败:
|
||
- 400:name 非法 / Content-Type 非 application/json / JSON 无效 / 空 body
|
||
- 401:unauthorized
|
||
- 413:超过 `max_upload_mb`
|
||
- 501:`configs_dir` 未配置
|
||
- 500:写盘失败
|
||
|
||
## 6. 主程序进程控制(agent 对外)
|
||
|
||
> 说明:该能力用于“启动/重启/关闭主程序(media-server)并选择加载哪个配置文件”。
|
||
>
|
||
> agent 启动 media-server 时会显式传入:`--config <resolved_config_path>`,因此不依赖 media-server 内部默认配置。
|
||
>
|
||
> 路径说明:
|
||
> - `agent.media_server_process` 下的 `exec_path/work_dir/configs_dir/pid_file` 支持绝对或相对路径;若为相对路径,则以 agent 启动参数 `--config <agent_config_path>` 的**配置文件所在目录**为基准解析。
|
||
> - `agent.config_path` 建议使用**绝对路径**;若使用相对路径:
|
||
> - `PUT /v1/config` 写盘时,以 **agent 进程当前工作目录(CWD)** 为基准;
|
||
> - 通过 `/v1/media-server/start|restart`(缺省 config)启动时,会把该相对路径原样传给 media-server,最终以 **media_server_process.work_dir** 为基准解析。
|
||
|
||
### 6.1 `POST /v1/media-server/start`
|
||
用途:启动本机 media-server(若已运行则幂等返回 ok;若已运行但 config 不同则 409)。
|
||
|
||
**Auth**:必须(401)
|
||
|
||
Body(可选,JSON):
|
||
```json
|
||
{"config":"cam1"}
|
||
```
|
||
|
||
说明:若请求 body 非空,则必须带 `Content-Type: application/json`;若 body 为空,可不带该 header。
|
||
|
||
`config` 解析规则:
|
||
- 为空/缺省:使用 `agent.config_path`
|
||
- 非空:只允许文件名/配置名(禁止包含 `/`、`\\`、`..`);若不带扩展名自动补 `.json`;最终从 `agent.media_server_process.configs_dir` 下解析为 `<configs_dir>/<config>.json`
|
||
|
||
Response 200:
|
||
```json
|
||
{"ok":true,"running":true,"pid":1234,"config_path":"/etc/rk3588sys/config.json"}
|
||
```
|
||
|
||
失败:
|
||
- 400:config 不合法 / config 文件不存在
|
||
- 409:已运行但 config 不同(提示使用 restart)
|
||
- 501:未启用进程控制(agent 配置 `agent.media_server_process.enable=false` 或未配置)
|
||
- 500:启动失败 / 写 pidfile 失败
|
||
|
||
### 6.2 `POST /v1/media-server/restart`
|
||
用途:重启本机 media-server(可切换 config)。
|
||
|
||
**Auth**:必须(401)
|
||
|
||
Body(可选,JSON):
|
||
```json
|
||
{"config":"cam1"}
|
||
```
|
||
|
||
说明:若请求 body 非空,则必须带 `Content-Type: application/json`;若 body 为空,可不带该 header。
|
||
|
||
Response 200:
|
||
```json
|
||
{"ok":true,"running":true,"pid":1234,"config_path":"/home/orangepi/Desktop/OrangePi3588Media/configs/cam1.json"}
|
||
```
|
||
|
||
失败:
|
||
- 400:config 不合法 / config 文件不存在
|
||
- 501:未启用进程控制
|
||
- 500:停止/启动失败
|
||
|
||
### 6.3 `POST /v1/media-server/stop`
|
||
用途:停止本机 media-server(未运行也返回 ok)。
|
||
|
||
**Auth**:必须(401)
|
||
|
||
Response 200:
|
||
```json
|
||
{"ok":true,"running":false,"pid":1234,"config_path":"/etc/rk3588sys/config.json"}
|
||
```
|
||
|
||
失败:
|
||
- 501:未启用进程控制
|
||
- 500:停止失败
|
||
|
||
### 6.4 `GET /v1/media-server/status`
|
||
用途:查询本机 media-server 是否在运行(以 agent 的 pidfile 记录为准)。
|
||
|
||
**Auth**:读接口(见 0.2)
|
||
|
||
Response 200:
|
||
```json
|
||
{"ok":true,"running":true,"pid":1234,"config_path":"/etc/rk3588sys/config.json"}
|
||
```
|
||
|
||
失败:
|
||
- 501:未启用进程控制
|
||
- 500:读取 pidfile/进程存活检测失败
|
||
|
||
## 7. 只读代理接口(agent 对外,推荐管理端统一走 agent)
|
||
|
||
### 7.1 `GET /v1/graphs`
|
||
代理 media-server:`GET /api/graphs`
|
||
|
||
### 7.2 `GET /v1/graphs/{name}`
|
||
代理 media-server:`GET /api/graphs/{name}`
|
||
|
||
### 7.3 `GET /v1/logs/recent?limit=200`
|
||
代理 media-server:`GET /api/logs/recent?limit=...`
|