GB28181国标设备注册源码实现
本文将讲解在VSS中国标设备REGISTER的接入流程从 gosip 收包、types.Request构建到RegisterLogic鉴权、DeviceUpsert落库以及上线/注销后触发的 Catalog、设备信息、心跳等下游任务。实现以VSS仓库源码为准。相关文档2.4.1.2 信令发送流水线注册后 Catalog /SendLogic、2.4.1.3 设备与通道在线状态在线状态与SetDeviceOnline。项目源码地址https://github.com/openskeye/go-vss1. 在Vss架构中的位置说明传输UDP/TCP 等由 gosip 监听Via 中携带 transport解析见getTransportProtocol。路由internal/handler/gbs_sip/routers.gosip.REGISTER→sip2.DO(..., new(gbssip.RegisterLogic))。解析ParseToRequestinternal/pkg/sip/utils.go把sip.Request转成types.Request。业务RegisterLogic.DOinternal/logic/gbs_sip/register.go。持久化RPCDevice.DeviceUpsert注册与注销统一走 upsert。注册成功后后续MESSAGECatalog、DeviceInfo、Keepalive、SUBSCRIBE、INVITE等信令都依赖SipCatalogLoopMap中缓存的types.Request与注册报文对齐的 From/Via/传输等见 2.4.1.2。2. 请求转为types.Request入口sip_handler.run在调用具体 Logic 前执行ParseToRequest(h.req)失败则400。ParseToRequest核心字段节选func ParseToRequest(req sip.Request) (*types.Request, error) { from, ok : req.From() if !ok || from.Address nil { return nil, errors.New(OnRegister, no from) } return types.Request{ ID: from.Address.User().String(), Source: req.Source(), Body: req.Body(), Original: req, DeviceAddr: sip.Address{ DisplayName: from.DisplayName, Uri: from.Address, }, Authorization: req.GetHeaders(Authorization), TransportProtocol: getTransportProtocol(req), }, nil }字段含义IDFrom URI 的 user 部分作为平台侧20 位设备国标编码实际长度校验在 Logic 内。Sourcereq.Source()用于devices.Address、Name等等价「注册来源/对端地址串」。Original完整 SIP 请求Authorization鉴权头使用UsePassword时参与校验。TransportProtocol由 Via 推断UDP/TCP/TLS/WS/WSS默认 UDP。3.RegisterLogic.DO流程3.1 流程图否是是否是否是失败否成功是否失败成功否是REGISTER 入站len ID 18?return nil -- sip_handler 回 200 OK 默认成功UsePassword 且无 Authorization?401 Unauthorized解析 Expires 头解析失败?401 UnauthorizedUsePassword?Digest auth 校验401 Unauthorized组装 recordexpire 0?Online0 注销Online1 上线DeviceUpsert500 系 Error 响应Online?CatalogLoop Offline HeartbeatLoop 仅 IDreturn 200异步 1s 后: CatalogLoop / SipSendCatalog / SipSendDeviceInfo / HeartbeatLoop3.2 关键步骤1设备 ID 长度func (l *RegisterLogic) DO() *types.Response { if len(l.req.ID) 18 { return nil18当前实现直接return nil。在sip_handler.success中res nil时仍会回复200 OK。若需拒绝非法 ID应改为显式BadRequest/Unauthorized避免「静默成功」这里需要自行修改。2密码与鉴权Config.Sip.UsePassword true且无 Authorization401提示 Authorization 为空。有 Authorization 时auth内Digest与配置Sip.Password比对REGISTER参与CalcResponse失败401。3Expires从Expires头取值当前代码用strings.Split(header.String(), :)取第二段再Atoi。格式需与库打印的 header 字符串一致否则解析失败走401expire 已过期文案实为解析失败分支。expire 0注销record.Online 0。4入库字段默认上线var ( now functions.NewTimer().Now() record devices.Item{ Devices: devices.Devices{ Name: l.req.Source, AccessProtocol: devices.AccessProtocol_4, DeviceUniqueId: l.req.ID, State: 1, Online: 1, Expire: uint64(now) uint64(expire), Address: l.req.Source, RegisterAt: uint64(now), }, }AccessProtocol_4固定为GB28181。Expire当前 Unix 秒 注册生存期秒。注册不经过SetDeviceOnline在线状态由DeviceUpsert一并写入与心跳里的SetDeviceOnline队列见 2.4.1.3是不同路径。5200 OK与附加 SIP 头BeforeResponse若存在Authorization且匹配成功在响应中附加Expires/User-Agent/Server并RemoveHeader(Allow)与设备交互兼容相关以现网设备为准。未带 Authorization时BeforeResponse里ok false可能不追加上述头依赖设备是否要求 Expires。6注销expire 0SipCatalogLoopOnline: falseCatalogLoopLogic从SipCatalogLoopMap移除该设备。SipHeartbeatLoop仅ID用于更新/清理心跳 map 中条目与上线时携带Now/RegisterExpireAt的完整结构不同。7上线成功后的异步任务Sleep 1sgo func() { time.Sleep(1 * time.Second) l.svcCtx.SipCatalogLoop - types.SipCatalogLoopReq{ Req: l.req, Online: true, Now: now } l.req.Caller functions.CallerFile(1) l.svcCtx.SipSendCatalog - l.req l.svcCtx.SipSendDeviceInfo - l.req l.svcCtx.SipHeartbeatLoop - types.SipHeartbeatLoopReq{ ID: record.DeviceUniqueId, Now: now, RegisterExpireAt: now int64(expire), } }()action作用SipCatalogLoopNow注册定时 Catalog判据见catalog_loop.go信令发送流水线中已经说明可能与预期不一致。SipSendCatalog立即拉目录经SendLogic→GBSSender.Catalog。SipSendDeviceInfo立即拉设备信息。SipHeartbeatLoopHeartbeatOfflineLogic每秒扫描RegisterExpireAt为本次注册到期 Unix 秒与HeartbeatTimeout等配合判定异常下线。延迟 1 秒降低被对端或中间网络丢弃的概率这里属于折中方案可以优化。4. 调试与排障建议现象可查点注册成功但无目录SipSendCatalog是否积压、SendLogic日志、SipCatalogLoopMap是否在注销时被清掉。一直 401UsePassword、Authorization 格式、密码与设备配置、Expires解析是否失败。ID 过短仍「成功」len(l.req.ID) 18返回 nil导致200这里可以明确错误码目前我返回的为200 ok。出站信令报设备未注册业务接口常查SipCatalogLoopMap设备须先完成注册流水线把Request放进 map。5. 源码索引文件说明core/app/sev/vss/internal/handler/gbs_sip/routers.goREGISTER 路由core/app/sev/vss/internal/logic/gbs_sip/register.goRegisterLogiccore/app/sev/vss/internal/pkg/sip/utils.goParseToRequest、传输协议core/app/sev/vss/internal/pkg/sip/sip_handler.go统一DO/响应码core/app/sev/vss/internal/types/types.goRequest、SipCatalogLoopReq、SipHeartbeatLoopReqcore/app/sev/vss/internal/logic/gbs_proc/catalog_loop.goCatalog 定时器core/app/sev/vss/internal/logic/gbs_proc/heartbeat_offline_loop.go注册到期与心跳超时下线