Files
monibuca/plugin/gb28181/pkg/devicechannel.go

307 lines
11 KiB
Go

package gb28181
import (
"gorm.io/gorm"
"strconv"
"time"
)
// ChannelStatus 通道状态类型
type ChannelStatus string
const (
ChannelOnStatus ChannelStatus = "ON"
ChannelOffStatus ChannelStatus = "OFF"
)
// DeviceChannel 设备通道信息
type DeviceChannel struct {
//CommonGBChannel // 通过组合继承 CommonGBChannel 的字段
ID string `gorm:"primaryKey" json:"ID"` // 数据库自增长ID
ChannelID string `json:"channelID" xml:"ChannelID"`
DeviceID string `json:"deviceID" xml:"DeviceID"` // 设备国标编号
ParentID string `json:"parentId" xml:"ParentID"` // 父节点ID
Name string `json:"name" xml:"Name"` // 通道名称
Manufacturer string `json:"manufacturer" xml:"Manufacturer"` // 设备厂商
Model string `json:"model" xml:"Model"` // 设备型号
Owner string `json:"owner" xml:"Owner"` // 设备归属
CivilCode string `json:"civilCode" xml:"CivilCode"` // 行政区域
Block string `json:"block" xml:"Block"` // 警区
Address string `json:"address" xml:"Address"` // 安装地址
Port int `json:"port" xml:"Port"` // 端口
Parental int `json:"parental" xml:"Parental"` // 是否有子设备
SafetyWay int `json:"safetyWay" xml:"SafetyWay"` // 信令安全模式
RegisterWay int `json:"registerWay" xml:"RegisterWay"` // 注册方式
CertNum string `json:"certNum" xml:"CertNum"` // 证书序列号
Certifiable int `json:"certifiable" xml:"Certifiable"` // 证书有效标识
ErrCode int `json:"errCode" xml:"ErrCode"` // 无效原因码
EndTime string `json:"endTime" xml:"EndTime"` // 证书终止有效期
Secrecy int `json:"secrecy" xml:"Secrecy"` // 保密属性
IPAddress string `json:"ipAddress" xml:"IPAddress"` // 设备/系统IP地址
Password string `json:"password" xml:"Password"` // 设备口令
PTZType int `json:"ptzType" xml:"Info>PTZType"` // 摄像机类型
PositionType int `json:"positionType" xml:"Info>PositionType"` // 摄像机位置类型
RoomType int `json:"roomType" xml:"Info>RoomType"` // 安装位置室内外属性
UseType int `json:"useType" xml:"Info>UseType"` // 用途属性
SupplyLightType int `json:"supplyLightType" xml:"Info>SupplyLightType"` // 摄像机补光属性
DirectionType int `json:"directionType" xml:"Info>DirectionType"` // 摄像机监视方位属性
Resolution string `json:"resolution" xml:"Info>Resolution"` // 摄像机支持的分辨率
BusinessGroupID string `json:"businessGroupId" xml:"Info>BusinessGroupID"` // 虚拟组织所属的业务分组ID
DownloadSpeed string `json:"downloadSpeed" xml:"Info>DownloadSpeed"` // 下载倍速
SVCSpaceSupportMod int `json:"svcSpaceSupportMod" xml:"Info>SVCSpaceSupportMode"` // 空域编码能力
SVCTimeSupportMode int `json:"svcTimeSupportMode" xml:"Info>SVCTimeSupportMode"` // 时域编码能力
StreamPushID int `json:"streamPushId"` // 关联的推流ID
StreamProxyID int `json:"streamProxyId"` // 关联的拉流代理ID
CreateTime string `json:"createTime"` // 创建时间
Status ChannelStatus `json:"status" xml:"Status"` // 设备状态
Longitude float64
Latitude float64
DeletedAt gorm.DeletedAt `yaml:"-"`
PTZTypeText string `json:"ptzTypeText"` // 云台类型描述字符串
GbLongitude float64 `json:"gbLongitude"`
GbLatitude float64 `json:"gbLatitude"`
}
// SetPTZType 设置云台类型并更新描述文本
func (d *DeviceChannel) SetPTZType(ptzType int) {
d.PTZType = ptzType
switch ptzType {
case 0:
d.PTZTypeText = "未知"
case 1:
d.PTZTypeText = "球机"
case 2:
d.PTZTypeText = "半球"
case 3:
d.PTZTypeText = "固定枪机"
case 4:
d.PTZTypeText = "遥控枪机"
case 5:
d.PTZTypeText = "遥控半球"
case 6:
d.PTZTypeText = "多目设备的全景/拼接通道"
case 7:
d.PTZTypeText = "多目设备的分割通道"
}
}
// DecodeFromXML 从 XML 元素解码设备通道信息
func DecodeFromXML(element interface{}) (*DeviceChannel, error) {
// TODO: 实现 XML 解码逻辑
// 这部分需要参考 Java 版本的 decode 方法实现
return nil, nil
}
// DecodeWithOnlyDeviceID 仅解码设备ID
func DecodeWithOnlyDeviceID(element interface{}) (*DeviceChannel, error) {
// TODO: 实现仅解码设备ID的逻辑
return nil, nil
}
// TableName 指定数据库表名
func (d *DeviceChannel) TableName() string {
return "gb28181_channel"
}
// NewDeviceChannel 创建新的设备通道实例
func NewDeviceChannel() *DeviceChannel {
now := time.Now().Format("2006-01-02 15:04:05")
return &DeviceChannel{
CreateTime: now,
Status: ChannelOffStatus,
}
}
// Encode 生成通道信息的XML内容
func (d *DeviceChannel) Encode(event string, serverDeviceID string) string {
if event == "" {
return d.getFullContent("", serverDeviceID)
}
switch event {
case "DEL", "DEFECT", "VLOST":
return "<Item>\n" +
"<DeviceId>" + d.DeviceID + "</DeviceId>\n" +
"<Event>" + event + "</Event>\n" +
"</Item>\n"
case "ON", "OFF":
return "<Item>\n" +
"<DeviceId>" + d.DeviceID + "</DeviceId>\n" +
"<Event>" + event + "</Event>\n" +
"</Item>\n"
case "ADD", "UPDATE":
return d.getFullContent(event, serverDeviceID)
default:
return ""
}
}
// getFullContent 生成完整的通道信息XML内容
func (d *DeviceChannel) getFullContent(event string, serverDeviceID string) string {
content := "<Item>\n" +
"<DeviceId>" + d.DeviceID + "</DeviceId>\n" +
"<Name>" + d.Name + "</Name>\n"
if len(d.DeviceID) > 8 {
typeCode := d.DeviceID[10:13]
switch typeCode {
case "200":
// 业务分组目录项
if d.Manufacturer != "" {
content += "<Manufacturer>" + d.Manufacturer + "</Manufacturer>\n"
}
if d.Model != "" {
content += "<Model>" + d.Model + "</Model>\n"
}
if d.Owner != "" {
content += "<Owner>" + d.Owner + "</Owner>\n"
}
if d.CivilCode != "" {
content += "<CivilCode>" + d.CivilCode + "</CivilCode>\n"
}
if d.Address != "" {
content += "<Address>" + d.Address + "</Address>\n"
}
if d.RegisterWay != 0 {
content += "<RegisterWay>" + strconv.Itoa(d.RegisterWay) + "</RegisterWay>\n"
}
if d.Secrecy != 0 {
content += "<Secrecy>" + strconv.Itoa(d.Secrecy) + "</Secrecy>\n"
}
case "215":
// 业务分组
if d.CivilCode != "" {
content += "<CivilCode>" + d.CivilCode + "</CivilCode>\n"
}
content += "<ParentID>" + serverDeviceID + "</ParentID>\n"
case "216":
// 虚拟组织目录项
if d.CivilCode != "" {
content += "<CivilCode>" + d.CivilCode + "</CivilCode>\n"
}
if d.ParentID != "" {
content += "<ParentID>" + d.ParentID + "</ParentID>\n"
}
content += "<BusinessGroupID>" + d.BusinessGroupID + "</BusinessGroupID>\n"
default:
// 其他类型
d.appendCommonInfo(&content)
}
}
if event != "" {
content += "<Event>" + event + "</Event>\n"
}
content += "</Item>\n"
return content
}
// appendCommonInfo 添加通用信息到XML内容
func (d *DeviceChannel) appendCommonInfo(content *string) {
if d.Manufacturer != "" {
*content += "<Manufacturer>" + d.Manufacturer + "</Manufacturer>\n"
}
if d.Model != "" {
*content += "<Model>" + d.Model + "</Model>\n"
}
if d.Owner != "" {
*content += "<Owner>" + d.Owner + "</Owner>\n"
}
if d.CivilCode != "" {
*content += "<CivilCode>" + d.CivilCode + "</CivilCode>\n"
}
if d.Block != "" {
*content += "<Block>" + d.Block + "</Block>\n"
}
if d.Address != "" {
*content += "<Address>" + d.Address + "</Address>\n"
}
if d.ParentID != "" {
*content += "<ParentID>" + d.ParentID + "</ParentID>\n"
}
if d.SafetyWay != 0 {
*content += "<SafetyWay>" + strconv.Itoa(d.SafetyWay) + "</SafetyWay>\n"
}
if d.RegisterWay != 0 {
*content += "<RegisterWay>" + strconv.Itoa(d.RegisterWay) + "</RegisterWay>\n"
}
if d.CertNum != "" {
*content += "<CertNum>" + d.CertNum + "</CertNum>\n"
}
if d.Certifiable != 0 {
*content += "<Certifiable>" + strconv.Itoa(d.Certifiable) + "</Certifiable>\n"
}
if d.ErrCode != 0 {
*content += "<ErrCode>" + strconv.Itoa(d.ErrCode) + "</ErrCode>\n"
}
if d.EndTime != "" {
*content += "<EndTime>" + d.EndTime + "</EndTime>\n"
}
if d.IPAddress != "" {
*content += "<IPAddress>" + d.IPAddress + "</IPAddress>\n"
}
if d.Port != 0 {
*content += "<Port>" + strconv.Itoa(d.Port) + "</Port>\n"
}
if d.Password != "" {
*content += "<Password>" + d.Password + "</Password>\n"
}
if d.Status != "" {
*content += "<Status>" + string(d.Status) + "</Status>\n"
}
if d.GbLongitude != 0 {
*content += "<Longitude>" + strconv.FormatFloat(d.GbLongitude, 'f', -1, 64) + "</Longitude>\n"
}
if d.GbLatitude != 0 {
*content += "<Latitude>" + strconv.FormatFloat(d.GbLatitude, 'f', -1, 64) + "</Latitude>\n"
}
// 添加Info标签内的信息
*content += "<Info>\n"
d.appendInfoContent(content)
*content += "</Info>\n"
}
// appendInfoContent 添加Info标签内的信息到XML内容
func (d *DeviceChannel) appendInfoContent(content *string) {
if d.PTZType != 0 {
*content += " <PTZType>" + strconv.Itoa(d.PTZType) + "</PTZType>\n"
}
if d.PositionType != 0 {
*content += " <PositionType>" + strconv.Itoa(d.PositionType) + "</PositionType>\n"
}
if d.RoomType != 0 {
*content += " <RoomType>" + strconv.Itoa(d.RoomType) + "</RoomType>\n"
}
if d.UseType != 0 {
*content += " <UseType>" + strconv.Itoa(d.UseType) + "</UseType>\n"
}
if d.SupplyLightType != 0 {
*content += " <SupplyLightType>" + strconv.Itoa(d.SupplyLightType) + "</SupplyLightType>\n"
}
if d.DirectionType != 0 {
*content += " <DirectionType>" + strconv.Itoa(d.DirectionType) + "</DirectionType>\n"
}
if d.Resolution != "" {
*content += " <Resolution>" + d.Resolution + "</Resolution>\n"
}
if d.BusinessGroupID != "" {
*content += " <BusinessGroupID>" + d.BusinessGroupID + "</BusinessGroupID>\n"
}
if d.DownloadSpeed != "" {
*content += " <DownloadSpeed>" + d.DownloadSpeed + "</DownloadSpeed>\n"
}
if d.SVCSpaceSupportMod != 0 {
*content += " <SVCSpaceSupportMode>" + strconv.Itoa(d.SVCSpaceSupportMod) + "</SVCSpaceSupportMode>\n"
}
if d.SVCTimeSupportMode != 0 {
*content += " <SVCTimeSupportMode>" + strconv.Itoa(d.SVCTimeSupportMode) + "</SVCTimeSupportMode>\n"
}
}
func (d *DeviceChannel) GetKey() string {
return d.ID
}