phase/0-infrastructure #1
290
doc/整合方案/SecMPS_整合方案_最终评估报告.md
Normal file
290
doc/整合方案/SecMPS_整合方案_最终评估报告.md
Normal file
@@ -0,0 +1,290 @@
|
||||
# SecMPS 整合方案 — 最终评估报告
|
||||
|
||||
> **评估日期**: 2026-05-16
|
||||
> **评估对象**: SecMPS_最终整合方案_v2.0.md
|
||||
> **参考依据**: Owl API 文档 / Owl GitHub / ZLMediaKit 官方文档 / ZLMediaKit GitHub / 数据字典设计
|
||||
|
||||
---
|
||||
|
||||
## 一、评估方法
|
||||
|
||||
以资深架构师经验,对整合方案进行三个维度的交叉验证:
|
||||
|
||||
1. **方案自洽性**:章节间逻辑是否一致,API 定义 ↔ 数据模型 ↔ 同步策略是否闭环
|
||||
2. **对 Owl+ZLMediaKit 的准确性**:方案定义的接口和流程是否与 Owl v1.3.0 / ZLMediaKit master 实际行为匹配
|
||||
3. **工程可落地性**:是否所有细节都有明确定义,是否存在"开发时再说"的模糊地带
|
||||
|
||||
共发现 **14 个问题**,按严重程度分为 P0(阻塞实施)、P1(影响质量)、P2(优化项)。
|
||||
|
||||
---
|
||||
|
||||
## 二、P0 — 必须修复(4 项)
|
||||
|
||||
### P0-1:第四章示例代码与 A3 接口规范矛盾
|
||||
|
||||
**问题描述**:
|
||||
§四示例代码(第 263-265 行)在每次同步时写入 `DeviceName = d.Name` 和 `DeviceCategory = d.Category`。但 A3 接口规范明确说"网关不碰管理员字段,首次入库写全量,后续仅更新网关负责的列"。这导致管理员手动改过的设备名称每次同步后被网关覆盖。
|
||||
|
||||
**影响**:管理员的设备重命名操作会被同步覆盖,用户投诉
|
||||
|
||||
**解决方案**:
|
||||
```csharp
|
||||
// 区分首次入库与增量更新
|
||||
if (entity.DeviceId == 0) // 首次入库
|
||||
{
|
||||
entity.DeviceName = d.Name;
|
||||
entity.DeviceCategory = d.Category;
|
||||
entity.DeviceGroup = d.Group;
|
||||
}
|
||||
// 增量更新:只写网关负责的字段
|
||||
entity.IsOnline = d.IsOnline ? "在线" : "离线";
|
||||
entity.IsParent = d.IsParent ? "是" : "否";
|
||||
entity.ExtraData = d.ExtraDataJson;
|
||||
entity.LastSyncTime = DateTime.UtcNow;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### P0-2:A3 设备同步中 `parentSourceId` → `ParentDeviceId` 解析链路缺失
|
||||
|
||||
**问题描述**:
|
||||
A3 请求中设备携带 `parentSourceId: "1001"`(第三方 ID),但 Vol.Pro 需要 `ParentDeviceId`(本地主键)。从第三方 ID 到本地主键的映射逻辑完全未定义。
|
||||
|
||||
**影响**:子设备无法挂到父设备下,设备树断裂
|
||||
|
||||
**解决方案**:
|
||||
同步前先做映射表查询:
|
||||
```csharp
|
||||
// 批量取出当前网关所有设备
|
||||
var allIds = await _db.base_device
|
||||
.Where(x => x.GatewayNodeId == nodeId)
|
||||
.ToDictionaryAsync(x => (x.AdapterCode, x.SourceId), x => x.DeviceId);
|
||||
|
||||
// 解析 parentSourceId
|
||||
int? parentDeviceId = null;
|
||||
if (!string.IsNullOrEmpty(d.ParentSourceId))
|
||||
allIds.TryGetValue((d.AdapterCode, d.ParentSourceId), out var pid);
|
||||
parentDeviceId = pid > 0 ? pid : null;
|
||||
|
||||
entity.ParentDeviceId = parentDeviceId;
|
||||
```
|
||||
补充到 §四 代码示例中。
|
||||
|
||||
---
|
||||
|
||||
### P0-3:网关重启注册时 NodeId 分配逻辑未定义
|
||||
|
||||
**问题描述**:
|
||||
网关重启再次调用 A1 `/register`,`gateway_nodes` 表中 `NodeCode` 已存在。当前文档只说注册流程,没有说明是覆盖还是报错。如果新建 NodeId,则 `base_device.GatewayNodeId` 指向旧 ID 断裂。
|
||||
|
||||
**影响**:网关重启后设备归属丢失
|
||||
|
||||
**解决方案**:
|
||||
A1 接口改为 Upsert 逻辑:
|
||||
```
|
||||
POST /register →
|
||||
NodeCode 匹配 → 更新 AdapterTypes/BaseUrl/IsOnline=在线 → 返回已有 NodeId
|
||||
NodeCode 不匹配 → 插入新记录 → 返回新 NodeId → 401(防止未授权节点)
|
||||
```
|
||||
补充到 §2.1 流程描述和 A1 API 规范中。
|
||||
|
||||
---
|
||||
|
||||
### P0-4:Owl 管理端口错误
|
||||
|
||||
**问题描述**:
|
||||
Owl README 和 Docker Compose 明确 Owl Web 管理端口 = `15123`。方案 `appsettings.json` 和 §七部署拓扑均写 `owl_host:80`。
|
||||
|
||||
**影响**:网关无法连接 Owl,所有视频功能不可用
|
||||
|
||||
**解决方案**:
|
||||
- `appsettings.json` 中 Owl BaseUrl → `http://owl_host:15123`
|
||||
- §七部署拓扑中 Owl 端口标记为 `:15123`
|
||||
- 注意:ZLM 自身 HTTP 端口是 `8000`,但由 Owl 内部调用,网关不接触
|
||||
|
||||
---
|
||||
|
||||
## 三、P1 — 影响实施质量(6 项)
|
||||
|
||||
### P1-1:PTZ 接口仅实现 continuous + stop
|
||||
|
||||
**问题描述**:
|
||||
owl_api_research.md §6.1 和 Owl GitHub 确认:Owl 代码中仅实现了 `continuous`(持续移动)和 `stop`(停止),`preset`(预置位)、`absolute`(绝对定位)、`relative`(相对定位)均返回错误。ONVIF PTZ 标记为 TODO。
|
||||
方案 §2.3 适配器矩阵和 B7 API 没有注明此限制。
|
||||
|
||||
**影响**:开发前端云台面板时做了预置位下拉等功能,部署后不可用
|
||||
|
||||
**解决方案**:
|
||||
- B7 接口标注:"仅支持 continuous (方向移动) + stop (停止)"
|
||||
- 前端云台面板:仅显示方向键(↑↓←→)+ 停止按钮,不显示预置位
|
||||
- OwlAdapter.PtzControlAsync 实现:ONVIF 设备直接返回错误
|
||||
|
||||
---
|
||||
|
||||
### P1-2:视频通道在 base_device 和 video_channel 中的双重身份不清
|
||||
|
||||
**问题描述**:
|
||||
§6 Owl 同步说 "Upsert base_device(ParentDeviceId=NVR) + video_channel",但 §3.6 层级示例中摄像机是叶子节点没有子设备。一个 Owl 通道到底是 base_device 的子记录还是 video_channel 的独立记录?还是两者都是?
|
||||
|
||||
**影响**:开发者不清楚通道数据写入哪张表的哪个字段
|
||||
|
||||
**解决方案**:
|
||||
明确:一个 Owl 通道 = 2 条记录:
|
||||
1. `base_device` 子记录(DeviceName="通道01", DeviceCategory=摄像机, ParentDeviceId=NVR的DeviceId, ExtraData=null)
|
||||
2. `video_channel` 扩展记录(DeviceId=通道的DeviceId, OwlStreamApp, OwlStreamName, HasPtz, SnapshotUrl)
|
||||
在 §3.6 层级示例中增加通道示例:
|
||||
```
|
||||
NVR (IsParent=是)
|
||||
├── 通道01 (base_device子记录, video_channel.OwlStreamApp="rtp")
|
||||
├── 通道02 (base_device子记录, video_channel.OwlStreamApp="rtp")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### P1-3:回放取流与实时取流走不同的 Owl 端点
|
||||
|
||||
**问题描述**:
|
||||
- 实时播放:`POST /channels/:id/play`
|
||||
- 回放播放:`GET /recordings/channels/:cid/index.m3u8?start_ms=&end_ms=&token=`
|
||||
两者是 Owl 的不同端点,方案 B6 只有一个 `/live` 路径。
|
||||
|
||||
**影响**:回放功能无法对接 Owl
|
||||
|
||||
**解决方案**:
|
||||
B6 拆分为两个端点:
|
||||
```
|
||||
GET /streams/{adapter}/{channelId}/live → Owl POST /channels/:id/play
|
||||
GET /streams/{adapter}/{channelId}/playback?start=&end= → Owl GET /recordings/channels/:cid/index.m3u8
|
||||
```
|
||||
IHasStreams 接口不变(已有 GetLiveUrlAsync 和 GetPlaybackUrlAsync),只修正 B 组 API 路径。
|
||||
|
||||
---
|
||||
|
||||
### P1-4:告警确认后 Vol.Pro 本地状态更新不闭环
|
||||
|
||||
**问题描述**:
|
||||
B9 调网关确认告警写回第三方成功,但 `iot_alarm.State` 谁来更新?当前文档没有说明这个回写链路。
|
||||
|
||||
**影响**:管理端显示告警仍为"未确认",需等下次 A4 同步才刷新
|
||||
|
||||
**解决方案**:
|
||||
B9 确认成功后,Vol.Pro 侧同步更新本地:
|
||||
```
|
||||
POST /alarms/{adapter}/{alarmId}/confirm 成功 →
|
||||
Vol.Pro 更新 iot_alarm SET State='已确认', ConfirmTime=NOW()
|
||||
```
|
||||
不需要网关二次推送。在 B9 接口规范中补充此说明。
|
||||
|
||||
---
|
||||
|
||||
### P1-5:video_record 同步策略缺失
|
||||
|
||||
**问题描述**:
|
||||
§六同步策略有设备同步、告警同步、反向控制,但没有录像记录的同步时机和频率。
|
||||
|
||||
**影响**:录像数据永远不会写入 video_record 表
|
||||
|
||||
**解决方案**:
|
||||
补充 §六:Owl 录像数据同步策略 ——
|
||||
- **方式一**(推荐):管理端点击"查看回放"时,网关实时调 Owl `GET /recordings` → 返回给管理端 → 同时写入 video_record 表
|
||||
- **方式二**(备选):网关定时(每 10 分钟)调 Owl `GET /recordings` → 走 A3 扩展同步 → 写入 video_record
|
||||
建议先用方式一,方式二在 Phase 3 优化时引入。
|
||||
|
||||
---
|
||||
|
||||
### P1-6:AdapterCode 双段格式无约束
|
||||
|
||||
**问题描述**:
|
||||
`"mc4:31号库房"` 中分隔符 `:` 和实例名字符集没有规范。如果实例名包含 `:` 会导致解析歧义。
|
||||
|
||||
**影响**:网关配置或同步时数据损坏
|
||||
|
||||
**解决方案**:
|
||||
定义格式规范(补充到 §2.2):
|
||||
```
|
||||
AdapterCode = "{AdapterType}:{InstanceName}"
|
||||
AdapterType: 字母数字,对应网关注册的 Adapter 类名(如 MC4、Owl)
|
||||
InstanceName: 字母数字下划线,对应具体网关实例(如 31ku)
|
||||
分隔符: ':'
|
||||
示例: "MC4:31ku"、"Owl:main"、"HikvisionISC:center"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、P2 — 优化项(4 项)
|
||||
|
||||
### P2-1:子设备离线状态级联规则(明确即可)
|
||||
|
||||
**问题描述**:
|
||||
§2.1 说网关离线 → 设备离线,但网关在线时父设备(采集器)离线,子设备是否级联标记离线?
|
||||
|
||||
**解决方案**:
|
||||
网关在 A3 同步时如实上报每个子设备的 isOnline(MC4.0 树中已有此信息),Vol.Pro 不做推断,信任网关数据。在 §六同步策略中补充此行说明即可。
|
||||
|
||||
---
|
||||
|
||||
### P2-2:数据字典初始化运维指引(补充附录)
|
||||
|
||||
**问题描述**:
|
||||
方案依赖 7 个数据字典(DeviceCategory 18 值、DeviceGroup 5 值、IsParent/IsOnline/Enable/IsControlPoint/AlarmLevel/State),但没有初始化指引。
|
||||
|
||||
**解决方案**:
|
||||
在文档末尾增加「附录 A:字典初始化清单」,列出每个字典的 Code/Name/Value 对照表,运维人员在 Vol.Pro 管理端按表创建。
|
||||
|
||||
---
|
||||
|
||||
### P2-3:video_channel 流地址字段用途说明(补充注释)
|
||||
|
||||
**问题描述**:
|
||||
video_channel 有 `OwlStreamApp/OwlStreamName/SnapshotUrl`,B6 取流实时调网关获取。这些字段的实际用途没说。
|
||||
|
||||
**解决方案**:
|
||||
注明为缓存——首次取流后写入 video_channel,下次先查缓存,缓存过期(或 Owl 重启后)再调 B6 实时获取。在 video_channel 表注释中补充说明。
|
||||
|
||||
---
|
||||
|
||||
### P2-4:Owl AI 事件可接入告警(建议纳入 Phase 1 可选范围)
|
||||
|
||||
**问题描述**:
|
||||
Owl 有 YOLO 本地检测 + `GET /events` 接口,AI 事件可走 A4 告警同步。
|
||||
|
||||
**解决方案**:
|
||||
在 OwlAdapter 中可选实现 IHasAlarms,将 `GET /events` 的 AI 检测事件映射为 StandardAlarm(AlarmLevel=提示或普通)。在 §六同步策略中补充可选说明,建议 Phase 1 范围中列入。
|
||||
|
||||
---
|
||||
|
||||
## 五、架构正确性确认
|
||||
|
||||
以下方面经过 Owl+ZLMediaKit 双文档验证,确认正确:
|
||||
|
||||
| 验证项 | 状态 |
|
||||
|--------|:--:|
|
||||
| 三层架构(前端→网关→Owl)不直接接触 ZLM | ✅ |
|
||||
| Owl 代理播放地址 `/proxy/sms/...` | ✅ |
|
||||
| Owl RTP 收流→ZLM 转协议→多格式输出的链路 | ✅ |
|
||||
| Owl Webhook 自动配置 ZLM(启动时 SetServerConfig) | ✅ |
|
||||
| JWT Token 管理 + RSA 加密登录 | ✅ |
|
||||
| 设备/通道 CRUD 对应 Owl API | ✅ |
|
||||
| 取流端点返回 WS-FLV/HTTP-FLV/HLS/WebRTC/RTMP/RTSP | ✅ |
|
||||
| Owl↔ZLM 联动(OpenRtpServer/CloseRtpServer/AddStreamProxy 等) | ✅ |
|
||||
| 按需拉流 + 30s 无人观看自动关闭(ZLM on_stream_none_reader → Owl 通知 ZLM 关流) | ✅ |
|
||||
| 云录像由 Owl 管理(ZLM MP4 录制→Owl on_record_mp4 hook→入库) | ✅ |
|
||||
| GB28181 设备注册与心跳是 SIP 层自动完成(Vol.Pro 只查 HTTP API) | ✅ |
|
||||
| 播放地址通过 Owl `/proxy/sms/` 反向代理到 ZLM(前端不直接访问 ZLM) | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 六、总结
|
||||
|
||||
| 优先级 | 数量 | 类型 |
|
||||
|:---:|:--:|------|
|
||||
| P0 | 4 | 阻塞性缺陷(代码矛盾、链路缺失、端口错误、注册逻辑缺失) |
|
||||
| P1 | 6 | 实施质量影响(PTZ限制、通道身份、回放端点、告警闭环、录像缺失、格式规范) |
|
||||
| P2 | 4 | 优化项(级联规则、字典指引、缓存说明、AI事件) |
|
||||
| ✅ | 12 | 已验证正确 |
|
||||
|
||||
**总体评价**:方案架构方向完全正确,Owl+ZLMediaKit 对接路径准确。14 个问题中 P0/P1 共 10 项,全部为配置级或接口路径级微调,不涉及架构推翻。修复后可直接作为实施基准。
|
||||
|
||||
---
|
||||
|
||||
> 本报告应作为 SecMPS_最终整合方案_v2.0.md 的修正依据。建议将 P0/P1 问题修复合入方案文档后再开始 Phase 1。
|
||||
Reference in New Issue
Block a user