设备监控模块
「NAS 服务器」主菜单提供三类设备的完整真实监控管理:服务器、NAS、摄像头,并支持摄像头 RTSP 视频预览。严格复用项目既有的 Model + Oper(AES) + Chain/Service + Handler + guarded 路由模式,新增依赖全部纯 Go 无 CGO。
功能覆盖
| 模块 | 能力 |
|---|---|
| 服务器 | 本机(gopsutil:CPU/内存/磁盘/网络/负载/温度/进程/运行时长)+ 远程 SSH 采集(/proc 解析)+ Agent 主动上报 |
| NAS | Agent 主动上报(飞牛、绿联等国产 NAS 推荐)、群晖 Synology API、TrueNAS/FreeNAS REST API、通用 SNMP fallback(负载/内存/存储表) |
| 摄像头 | ONVIF 设备发现/信息/码流地址(自写 SOAP + WS-Security)、RTSP 探活、RTSP 视频预览 |
| 告警 | CPU/内存/磁盘/温度阈值 + 离线告警,状态转换去重,复用通知链(bark/tg/webhook) |
| 时序 | MetricSnapshot 历史快照 + 自动清理(默认保留 30 天) |
后端结构
internal/
├── monitor/ 设备监控包(16 文件,每文件 <400 行)
│ ├── types.go Metrics/Thresholds/Credentials + 默认阈值
│ ├── collector.go Collector 接口 + Registry(按 type+protocol 分发)
│ ├── host.go 本机采集(gopsutil/v4)
│ ├── ssh.go + ssh_parse.go 远程 SSH 采集 + /proc 解析(单会话脚本,易测)
│ ├── nas.go NAS 分发 + JSON 宽松取值 helper
│ ├── nas_synology.go 群晖 auth.cgi/entry.cgi
│ ├── nas_truenas.go TrueNAS /api/v2.0 + Token
│ ├── nas_snmp.go gosnmp(hrStorage/laLoad/mem)
│ ├── camera.go + onvif.go ONVIF SOAP 薄层 + RTSP 探活
│ ├── rtsp_probe.go gortsplib DESCRIBE 探活
│ ├── rtsp_session.go RTSP→WS 拉流会话(多观众复用 + annexB)
│ ├── rtsp_proxy.go RTSPProxy(WS 鉴权/升级/读写泵/全局观众上限)
│ ├── service.go Store 接口 + 单 ticker 扫表采集调度
│ ├── alert.go 阈值评估 + 状态转换去重
│ └── json.go JSON 辅助
├── db/models/models.go +MonitorTarget / MetricSnapshot / MonitorAlert
├── db/oper/monitor.go CRUD + AES 凭据 + Snapshot(含网络速率) + Alert 状态机
├── db/db.go AutoMigrate 追加三表
├── api/v1/monitor*.go Handler(CRUD/probe/collect/metrics + alerts + stream)
├── api/router.go /monitors + /monitor/alerts(guarded)+ /monitor/cameras/:id/stream(WS,guarded 外)
└── app/app.go 装配 + go monSvc.Run + 每日清理 cron采集器分发矩阵
Registry 按 (type, protocol) 注册(ResolveProtocol 在 protocol 为空时按 type/host 推断):
| type | protocol | 采集器 | 凭据(AES 加密) |
|---|---|---|---|
| host | local | HostCollector(gopsutil,忽略 Host/凭据) | 无 |
| host | ssh | SSHCollector | username + password |
| host / nas | agent | AgentWSHub 主动上报(绕过 Collector) | 每设备独立 secret |
| nas | local | HostCollector(gopsutil,支持 bind mount 磁盘路径) | 无 |
| nas | api | NASCollector → synology / truenas | username + password(TrueNAS 用 API Token) |
| nas | snmp | NASCollector → gosnmp | username = community |
| camera | onvif | CameraCollector(SOAP,自动回填 RTSPURL) | username + password |
| camera | rtsp | CameraCollector(gortsplib 探活) | rtsp_url |
凭据由 Oper.Credentials 解密注入 Collector,Collector 不持久化明文。
采集调度
Service.Run 单 ticker(10s)扫表 → 到点(LastCheckedAt + IntervalSec ≤ now)的 target 并发采集(per-target context.WithTimeout + panic 恢复)→ RecordSnapshot(对比上次快照算网络速率)→ Alerter.Evaluate。target 增删/interval 改无需动调度(与 ws.Broadcaster.Run 同模式)。每日 3 点清理 30 天前快照。
RTSP→WebSocket 代理
浏览器不能直播 RTSP。RTSPProxy 用 gortsplib 拉流 → 解 H.264 → annexB 帧 → gorilla/websocket 转发,前端 jessibuca(wasm) 解码。一路摄像头单路拉流、多观众复用(refCount + 30s 保活窗口);全局观众上限(默认 8,防资源耗尽);鉴权复用 ws.go 的 ?token=<jwt> + CheckOrigin 白名单。部署见 public/jessibuca/README.md。
API 端点
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /monitors | 列监控目标 |
| POST | /monitors | 添加(TargetInput) |
| POST | /monitors/agents | 创建服务器/NAS Agent(`type=host |
| PUT | /monitors/:id | 更新(密码留空不改) |
| DELETE | /monitors/:id | 删除(连带快照/告警) |
| POST | /monitors/:id/probe | 探活 |
| POST | /monitors/:id/collect | 手动采集,返回当前 Metrics |
| GET | /monitors/:id/metrics | 历史快照(?since=&limit=) |
| GET | /monitor/alerts | 告警列表(?target_id=&unread=) |
| POST | /monitor/alerts/:id/read | 标已读 |
| GET | /monitor/cameras/:id/stream | RTSP→WS 视频流(?token=&url=) |
告警阈值
MonitorTarget.Thresholds 存 JSON,空字段回退默认:
{"cpu_usage":90, "mem_usage":90, "disk_usage":90, "temp":75, "offline":true}超阈值 +10 个点以内为 warning,更高为 danger;仅「未触发→触发」时新建告警并通知(去重),「触发→恢复」时静默 Resolve。
依赖(纯 Go,无 CGO)
github.com/shirou/gopsutil/v4— 本机系统指标(v4 是当前主线)github.com/bluenviron/gortsplib/v5— RTSP 客户端(v4 已弃用,用 v5)github.com/gosnmp/gosnmp— NAS SNMP fallback- 已复用:
golang.org/x/crypto/ssh(远程采集)、gorilla/websocket(RTSP-WS 出口)
测试
go test ./internal/monitor/ 覆盖:/proc 解析、ONVIF 标签提取、阈值解析、Registry 分发、本机采集烟雾、告警状态转换去重、离线告警。RTSP 代理/真实设备采集因需硬件不在单测范围。