package service import ( "bytes" "encoding/json" "errors" "fmt" "strconv" "strings" "time" "vamicro/camera-common/models" "vamicro/config" "vamicro/extend/util" gbModels "vamicro/gb28181-service/models" "basic.com/gb28181api.git" "basic.com/pubsub/protomsg.git" "basic.com/valib/bhomeclient.git" "basic.com/valib/bhomedbapi.git" "basic.com/valib/logger.git" "github.com/jinzhu/gorm" uuid "github.com/satori/go.uuid" ) type Gb28181Service struct { bk bhomeclient.Broker } func NewGb28181Service(broker bhomeclient.Broker) *Gb28181Service { return &Gb28181Service{ bk: broker, } } func (s Gb28181Service) Edit(gbConfig gbModels.Gb28181Config) bool { timeUnix := time.Now().Unix() fmtTimeStr := time.Unix(timeUnix, 0).Format("2006-01-02 15:04:05") gbConfig.UpdateTime = fmtTimeStr var gbConf gbModels.Gb28181Config rows, _ := gbConf.Select() if rows > 0 { //已存在,编辑 gbConfig.Id = gbConf.Id gbConfig.ServerPort = 8060 data := util.Struct2Map(gbConfig) if err := models.GetDB().Table(gbConf.TableName()).Updates(data).Error; err != nil { return false } } else { //新增 gbConfig.Id = uuid.NewV4().String() gbConfig.ServerPort = 8060 if err := models.GetDB().Table(gbConf.TableName()).Create(&gbConfig).Error; err != nil { return false } } setGbIp := getGbIp() if setGbIp != "" { //接入国标的平台树 var gbApi gb28181api.Gb28181Api gb28181api.Init(setGbIp, gbConfig.ServerPort) //设置国标平台基础配置 gbApi.SetPlatformServerInfo(gb28181api.GbServerInfo{ Name: "贝思科国标服务", PublicID: gbConfig.PublicId, GbServerPort: gbConfig.GbServerPort, RtspServrPort: 7554, HTTPClientIP: "", HTTPClientPort: gbConfig.ServerPort, RegisterAuth: gbConfig.IsAuth, GbPasswd: gbConfig.Password, }) //先更新资源 gbApi.UpdateAllResource() } else { logger.Error("刷新国标服务时,setGbIp不能为空!!!!") return false } return true } type gbDevAndArea struct { PublicId string ParentId string } type VssTable struct { Vd []gbModels.VssDev `json:"vd"` Du map[string]gbModels.VssDomainUnit `json:"du"` Vc map[string]gbModels.VssChannel `json:"vc"` GbCam []models.Camera `json:"gbCam"` } //获取国标服务使用的ip(可能是漂移ip) func getGbIp() string { setGbIp := "" localIp, _, _ := util.GetLocalIP(config.Server.NetworkAdapter) //没有配置,则取本机ip var clusterApi bhomedbapi.ClusterApi b, c := clusterApi.FindCluster() logger.Debug("FindCluster b:", b, " c:", c) if b && c.Nodes != nil && len(c.Nodes) > 0 { //在集群内,则非漂移master节点,使用漂移ip,否则使用本机ip。此处漂移master节点,使用漂移ip访问不到本机,这个原因是iptables转换策略改的是本机入的,漂移ip会给到本机的8060, //但是本机出的不走这个策略,所以本机使用漂移ip访问不到本机的8060 driftMasterId := "" for _, n := range c.Nodes { if n.DriftState == "master" { //查看当前漂移master节点是否是本机 driftMasterId = n.NodeId break } } if driftMasterId != "" { if driftMasterId == config.Server.AnalyServerId { //当前节点是漂移master setGbIp = localIp } else { setGbIp = c.VirtualIp //取漂移ip } } } else { setGbIp = localIp } return setGbIp } func (s Gb28181Service) GetAllSubServer() (bool, interface{}) { setGbIp := getGbIp() if setGbIp == "" { return false, errors.New("获取国标ip失败") } var gbConfig gbModels.Gb28181Config rows, _ := gbConfig.Select() if rows == 0 { //已存在,编辑 return false, errors.New("请先设置国标配置") } gbConfig.ServerPort = 8060 var gbApi gb28181api.Gb28181Api gb28181api.Init(setGbIp, gbConfig.ServerPort) devices, b := gbApi.GetAllDevices() return b, devices } // UpdateGb28181Data 从videosvr的sqlite3.db中获取数据, 写入到当前数据库的同步表 func (s Gb28181Service) UpdateGb28181Data() (bool, error) { setGbIp := getGbIp() if setGbIp == "" { return false, errors.New("获取国标ip失败") } var gbConfig gbModels.Gb28181Config rows, _ := gbConfig.Select() if rows == 0 { //已存在,编辑 return false, errors.New("请先设置国标配置") } gbConfig.ServerPort = 8060 var gbApi gb28181api.Gb28181Api gb28181api.Init(setGbIp, gbConfig.ServerPort) var err error tx := models.GetDB().Begin() defer func() { if err != nil && tx != nil { tx.Rollback() logger.Debug("updateGb28181Data err:", err) } }() // 清除旧数据,以videosvr数据为准 err = tx.Exec("delete from " + gbModels.VssDev{}.TableName() + "").Error if err != nil { return false, err } err = tx.Exec("delete from " + gbModels.VssDomainUnit{}.TableName() + "").Error if err != nil { return false, err } err = tx.Exec("delete from " + gbModels.VssChannel{}.TableName() + "").Error if err != nil { return false, err } // 获取所有下级 devices, flag := gbApi.GetAllDevices() logger.Debug("gb28181 group devices:", devices) if flag && devices != nil && len(devices) > 0 { if err = batchSaveGbDev(tx, devices); err != nil { return false, err } for _, d := range devices { // 获取下级的所有通道个目录. 数据来源于vsschannel表, resType = 1 是通道, resType = 2 表示目录 allCams, allGroups, b := gbApi.GetAllCamerasAndGroupsByDevID(d.PublicID) logger.Debug("publicId:", d.PublicID, " b:", b, " len(allCams):", len(allCams), " len(allGroups)", len(allGroups)) if b && len(allCams) > 0 { //t1 := time.Now() if err = batchSaveGbChannel(tx, allCams); err != nil { logger.Debug("batchSaveGbChannel err:", err) return false, err } //logger.Debug("batchSaveGbChannel耗时:", time.Since(t1)) } // 将resType = 2 的区域信息, 合并到domainUnit表. // 该功能后来被屏蔽过, 应该是和domainUnit的数据有冲突. 一个通道出现了两个组织. 所以干脆以domainUnit为准, 忽略了这里的组织 // 但是也有可能导致结构不全, 比如普洱国标整合了这些区域信息后就是正确的. // 可根据不同的结构可以进行调整. 暂时先放开, 保证有尽可能多的的组织结构 if len(allGroups) > 0 { //t1 := time.Now() if err = batchSaveGbDomainUnit(tx, allGroups); err != nil { return false, err } //logger.Debug("batchSaveGbDomainUnit耗时:", time.Since(t1)) } } } // 获取所有国标区域 domainUnits, b := gbApi.GetAllDomainUnit() logger.Debug("gb28181 gb units:", len(domainUnits)) if b && domainUnits != nil && len(domainUnits) > 0 { if err = batchSaveGbDomainUnit(tx, domainUnits); err != nil { return false, err } } tx.Commit() return true, nil } func batchSaveGbDev(tx *gorm.DB, dArr []gb28181api.DeviceInfo) error { var buffer bytes.Buffer sql := "insert into `" + gbModels.VssDev{}.TableName() + "` (`publicId`,`name`,`ip`,`port`,`corp`,`parentId`,`username`,`passwd`,`devMode`,`alive`) values " if _, err := buffer.WriteString(sql); err != nil { return err } for i, d := range dArr { if i == len(dArr)-1 { buffer.WriteString(fmt.Sprintf("('%s','%s','%s',%d,'%s','%s','%s','%s','%s',%d);", d.PublicID, d.Name, d.IP, d.Port, d.Corp, d.Parentid, d.Username, d.Passwd, d.Devmode, d.Alive)) } else { buffer.WriteString(fmt.Sprintf("('%s','%s','%s',%d,'%s','%s','%s','%s','%s',%d),", d.PublicID, d.Name, d.IP, d.Port, d.Corp, d.Parentid, d.Username, d.Passwd, d.Devmode, d.Alive)) } } return tx.Exec(buffer.String()).Error } func batchSaveGbChannel(tx *gorm.DB, arr []gb28181api.CameraInfo) error { var buffer bytes.Buffer sql := "insert into `" + gbModels.VssChannel{}.TableName() + "` (`publicId`,`devPubId`,`resType`,`name`,`alive`,`corp`,`model`,`owner`,`civilCode`,`address`,`parentId`,`ip`,`port`,`longitude`,`latitude`,`ptzType`,`streamType`,`realRtspUrl`) values " if _, err := buffer.WriteString(sql); err != nil { return err } for i, c := range arr { if i == len(arr)-1 { buffer.WriteString(fmt.Sprintf("('%s','%s',%d,'%s',%d,'%s','%s','%s','%s','%s','%s','%s',%d,%f,%f,%d,%d,'%s');", c.PublicID, c.DevPubID, c.ResType, c.Name, c.Alive, c.Corp, c.Model, c.Owner, c.CivilCode, c.Address, c.ParentID, c.IP, c.Port, c.Latitude, c.Latitude, c.PtzType, c.StreamType, c.RealRtspURL)) } else { buffer.WriteString(fmt.Sprintf("('%s','%s',%d,'%s',%d,'%s','%s','%s','%s','%s','%s','%s',%d,%f,%f,%d,%d,'%s'),", c.PublicID, c.DevPubID, c.ResType, c.Name, c.Alive, c.Corp, c.Model, c.Owner, c.CivilCode, c.Address, c.ParentID, c.IP, c.Port, c.Latitude, c.Latitude, c.PtzType, c.StreamType, c.RealRtspURL)) } } return tx.Exec(buffer.String()).Error } func batchSaveGbDomainUnit(tx *gorm.DB, uArr []gb28181api.DomainUnit) error { var buffer bytes.Buffer sql := "insert into `" + gbModels.VssDomainUnit{}.TableName() + "` (`publicId`,`devPubId`,`resType`,`name`,`parentId`,`totalNum`,`onlineNum`) values " if _, err := buffer.WriteString(sql); err != nil { return err } for i, u := range uArr { if i == len(uArr)-1 { buffer.WriteString(fmt.Sprintf("('%s','%s',%d,'%s','%s',%d,%d);", u.PublicID, u.DevPubID, u.ResType, u.Name, u.ParentID, u.TotalNum, u.OnlineNum)) } else { buffer.WriteString(fmt.Sprintf("('%s','%s',%d,'%s','%s',%d,%d),", u.PublicID, u.DevPubID, u.ResType, u.Name, u.ParentID, u.TotalNum, u.OnlineNum)) } } return tx.Exec(buffer.String()).Error } func GetPidsByRecursion(uIdMap *map[string]gbDevAndArea, parentId string, pIds *string) { if unit, ok := (*uIdMap)[parentId]; ok { *pIds = "," + parentId + "," + *pIds GetPidsByRecursion(uIdMap, unit.ParentId, pIds) } else { *pIds = ",0," + *pIds *pIds = strings.Replace(*pIds, ",,", ",", -1) return } } type GbTreeMenu struct { Id string `json:"id"` Name string `json:"name"` Type string `json:"type"` Children []GbTreeMenu `json:"children"` Checked bool `json:"checked"` //是否选中 Alive int `json:"alive"` //是否存活,取决于国标库是否动态更新 civilCode string parentId string } //获取当前国标的目录树结构 func (s Gb28181Service) GetGbCurrentTree() []GbTreeMenu { menus := make([]GbTreeMenu, 0) var gbConfig gbModels.Gb28181Config if rows, _ := gbConfig.Select(); rows == 0 { return menus } var vssDevices gbModels.VssDev var vssDomainUnit gbModels.VssDomainUnit var vssChannel gbModels.VssChannel devices, _ := vssDevices.FindAll() domainUnits, _ := vssDomainUnit.FindAll() gbAllCamAndGroups, _ := vssChannel.FindAll() channelsArry := make([]gbModels.VssChannel, 0) groupArr := make([]gbModels.VssChannel, 0) civilM := make(map[string]gbModels.VssChannel, 0) for _, gcg := range gbAllCamAndGroups { if gcg.ResType == 1 { //摄像机资源 channelsArry = append(channelsArry, gcg) } else if gcg.ResType == 2 { //group资源 civilM[gcg.CivilCode] = gcg civilM[gcg.PublicID] = gcg groupArr = append(groupArr, gcg) } } // 查询当前保存的摄像机, 添加已选择的标志 var camCursor models.Camera selectedCams, _ := camCursor.FindCamerasByType(models.TYPE_GB28181_CAMERA, "") logger.Debug("GetGbCurrentTree len(selectedCams):", len(selectedCams)) ncM := make(map[string]string, 0) selectedCamsMap := make(map[string]models.Camera) for _, gc := range selectedCams { selectedCamsMap[gc.Id] = gc ncM[gc.Id] = gc.Id } unitMap := make(map[string]gbModels.VssDomainUnit, 0) for _, u := range domainUnits { unitMap[u.PublicID] = u } movedM := make(map[string]string, 0) for _, d := range devices { mu := GbTreeMenu{ Id: d.PublicID, Name: d.Name, } if mu.Name == "" { mu.Name = mu.Id } if len(d.PublicID) > 13 && d.PublicID[10:13] == "132" { //表示这个设备是摄像机,并且不在下级平台下 mu.Type = "camera" mu.Alive = d.Alive if _, ok := selectedCamsMap[mu.Id]; ok { mu.Checked = true ncM[mu.Id] = mu.Id } movedM[mu.Id] = mu.Id } else { mu.Type = "menu" logger.Debug("len(groupArr): ", len(groupArr)) rootChk := false for _, tmpChan := range groupArr { if tmpChan.ParentId == d.PublicID { child := GbTreeMenu{ Id: tmpChan.PublicID, Name: tmpChan.Name, Type: "menu", parentId: d.PublicID, civilCode: tmpChan.CivilCode, } recurseGbMenu(d.PublicID, &child, &domainUnits, unitMap, civilM, &groupArr, &channelsArry, selectedCamsMap, movedM, ncM) if _, chk := ncM[child.Id]; chk { child.Checked = true rootChk = true } mu.Children = append(mu.Children, child) } } for _, tmpUnit := range domainUnits { if tmpUnit.ParentID == d.PublicID || tmpUnit.ParentID == "" { child := GbTreeMenu{ Id: tmpUnit.PublicID, Name: tmpUnit.Name, Type: "menu", parentId: d.PublicID, civilCode: tmpUnit.PublicID, } recurseGbMenu(d.PublicID, &child, &domainUnits, unitMap, civilM, &groupArr, &channelsArry, selectedCamsMap, movedM, ncM) if _, chk := ncM[child.Id]; chk { child.Checked = true rootChk = true } mu.Children = append(mu.Children, child) } } mu.Checked = rootChk } menus = append(menus, mu) } logger.Debug("len(movedM):", len(movedM), " len(channelsArry):", len(channelsArry)) invalidMenu := GbTreeMenu{ Id: "invalid", Name: "无上级分组!!!", Type: "menu", parentId: "", } var ignoredPIds []string invalidMenuMap := make(map[string][]GbTreeMenu, 0) for _, c := range channelsArry { if _, ok := movedM[c.PublicID]; !ok { ignoredPIds = append(ignoredPIds, c.PublicID) if cvArr, cvO := invalidMenuMap[c.CivilCode]; !cvO { chk := false if _, chk = ncM[c.PublicID]; chk { chk = true ncM[c.CivilCode] = c.CivilCode } invalidMenuMap[c.CivilCode] = append([]GbTreeMenu{}, GbTreeMenu{ Id: c.PublicID, Name: c.Name, Type: "camera", parentId: invalidMenu.Id, Alive: c.Alive, Checked: chk, }) } else { chk := false if _, chk = ncM[c.PublicID]; chk { chk = true ncM[c.CivilCode] = c.CivilCode } cvArr = append(cvArr, GbTreeMenu{ Id: c.PublicID, Name: c.Name, Type: "camera", parentId: invalidMenu.Id, Alive: c.Alive, Checked: chk, }) invalidMenuMap[c.CivilCode] = cvArr } movedM[c.PublicID] = c.PublicID } } for k, v := range invalidMenuMap { icName := k if chd, cvIn := civilM[k]; cvIn { icName = chd.Name } invalidChild := GbTreeMenu{ Id: k, Name: icName, Type: "menu", Children: v, parentId: "invalid", } if _, chk := ncM[invalidChild.Id]; chk { invalidChild.Checked = true invalidMenu.Checked = true } invalidMenu.Children = append(invalidMenu.Children, invalidChild) } if len(invalidMenu.Children) > 0 { menus = append(menus, invalidMenu) } logger.Debug("len(ignoredIds):", len(ignoredPIds)) //logger.Debug("menus", menus) return menus } //获取当前国标的所有摄像机资源信息, 平铺树 func (s Gb28181Service) GetGbCameras() []GbTreeMenu { var vssChannel gbModels.VssChannel gbAllCamAndGroups, _ := vssChannel.FindAll() channelsArry := make([]GbTreeMenu, 0) for _, gcg := range gbAllCamAndGroups { if gcg.ResType == 1 { //摄像机资源 channelsArry = append(channelsArry, GbTreeMenu{ Id: gcg.PublicID, Name: gcg.Name, Type: "camera", Children: nil, Checked: false, Alive: gcg.Alive, civilCode: gcg.CivilCode, parentId: gcg.ParentId, }) } } return channelsArry } func recurseGbMenu(devPubId string, mu *GbTreeMenu, uArr *[]gbModels.VssDomainUnit, unitM map[string]gbModels.VssDomainUnit, civilM map[string]gbModels.VssChannel, groupArr *[]gbModels.VssChannel, cArr *[]gbModels.VssChannel, gbcM map[string]models.Camera, movedM map[string]string, ncm map[string]string) { //递归处理所有下级资源组,以及资源组下的摄像机 for _, cGroup := range *groupArr { if cGroup.ParentId == mu.Id || cGroup.ParentId == mu.civilCode { child := GbTreeMenu{ Id: cGroup.PublicID, Name: cGroup.Name, Type: "menu", civilCode: cGroup.ChanPubID, parentId: mu.Id, } recurseGbMenu(devPubId, &child, uArr, unitM, civilM, groupArr, cArr, gbcM, movedM, ncm) if _, chk := ncm[child.Id]; chk { child.Checked = true ncm[mu.Id] = mu.Id } mu.Children = append(mu.Children, child) } } //递归处理所有下级行政区域,以及区域下的摄像机 for _, u := range *uArr { if u.ParentID == mu.Id { child := GbTreeMenu{ Id: u.PublicID, Name: u.Name, Type: "menu", civilCode: u.PublicID, parentId: mu.Id, } recurseGbMenu(devPubId, &child, uArr, unitM, civilM, groupArr, cArr, gbcM, movedM, ncm) if _, chk := ncm[child.Id]; chk { child.Checked = true ncm[mu.Id] = mu.Id } mu.Children = append(mu.Children, child) } } //有些摄像机是挂在当前这一级平台下的 parentChecked := false for _, c := range *cArr { if c.DevPubID == devPubId { if _, ok := movedM[c.PublicID]; !ok { //未处理过此摄像机 if c.ParentId != "" { _, in := unitM[c.ParentId] _, inUnitCiv := unitM[c.CivilCode] _, inCivil := civilM[c.CivilCode] _, inChanPub := civilM[c.ParentId] //如果目录树中没有此摄像机的parentId,并且civilCode表中也没有,则挂到平台根目录下 if !in && !inCivil && !inUnitCiv && !inChanPub { cu := GbTreeMenu{ Id: c.PublicID, Name: c.Name, Type: "camera", Alive: c.Alive, } if _, ok := gbcM[cu.Id]; ok { cu.Checked = true parentChecked = true ncm[cu.Id] = cu.Id } mu.Children = append(mu.Children, cu) movedM[c.PublicID] = c.PublicID } else { if c.ParentId == mu.Id || c.CivilCode == mu.Id || c.CivilCode == mu.civilCode { cu := GbTreeMenu{ Id: c.PublicID, Name: c.Name, Type: "camera", Alive: c.Alive, } if _, ok := gbcM[cu.Id]; ok { cu.Checked = true parentChecked = true ncm[cu.Id] = cu.Id } mu.Children = append(mu.Children, cu) movedM[c.PublicID] = c.PublicID } } } else { //摄像机的parentId为空,则挂到根目录下 cu := GbTreeMenu{ Id: c.PublicID, Name: c.Name, Type: "camera", Alive: c.Alive, } if _, ok := gbcM[cu.Id]; ok { cu.Checked = true parentChecked = true ncm[cu.Id] = cu.Id } mu.Children = append(mu.Children, cu) movedM[c.PublicID] = c.PublicID } } } } mu.Checked = parentChecked if parentChecked { ncm[mu.Id] = mu.Id } } //刷新后保存国标摄像机的配置,(目前的需求是国标摄像机配置路数不能超过500路) func (s Gb28181Service) SaveGb28181CamTree(reqBody []GbTreeMenu) (bool, error) { logger.Debug("SaveGb28181CamTree reqBody:", reqBody) //首先检查待配置的摄像机数量是否超过限制路数 totalCount := 0 recurseGbMenuCount(reqBody, &totalCount) limit := config.Server.GbCamCount if limit <= 0 { limit = 500 } if totalCount > limit { return false, errors.New("国标摄像机数量最高不能超过:" + strconv.Itoa(limit) + "路") } var vd gbModels.VssDev var du gbModels.VssDomainUnit var vc gbModels.VssChannel devices, _ := vd.FindAll() uM := du.FindAllMap() gbcM := vc.FindAllMap() //VSSChannelTbl表中可能保存有目录结构,resType=2 for _, d := range devices { if len(d.PublicID) > 13 && d.PublicID[10:13] == "132" { //是个摄像机 logger.Debug("SaveGb28181CamTree d:", d) } else { //是个平台 if _, ok := uM[d.PublicID]; !ok { logger.Debug("SaveGb28181CamTree not contain d.id=>", d.PublicID, " d.name=>", d.Name) uM[d.PublicID] = gbModels.VssDomainUnit{ DevPubID: d.PublicID, PublicID: d.PublicID, Name: d.Name, } } } } var gbcModel models.Camera gbCams, _ := gbcModel.FindCamerasByType(models.TYPE_GB28181_CAMERA, "") logger.Debug("GetGbCurrentTree len(gbCams):", len(gbCams)) camCache := make(map[string]models.Camera, 0) for _, gc := range gbCams { camCache[gc.Id] = gc } //1.摄像机所属的目录吸入area表中 //2.摄像机写入camera表中 //3.建立camera和area的关联关系 var err error tx := models.GetDB().Begin() defer func() { if err != nil && tx != nil { tx.Rollback() logger.Debug("saveGb28181CamTree err:", err) } }() //清除旧的数据 err = tx.Exec("delete from " + models.Camera{}.TableName() + " where type=1").Error if err != nil { return false, err } err = tx.Exec("delete from " + models.Area{}.TableName() + " where type=1").Error if err != nil { return false, err } err = tx.Exec("delete from " + models.CameraArea{}.TableName() + " where cameraId not in (select id from cameras)").Error if err != nil { return false, err } //写入新的国标摄像机 uIdMap := make(map[string]gbDevAndArea, 0) if err = recurseInsertGbCamOrUnit(tx, reqBody, uM, gbcM, uIdMap, "0", camCache); err != nil { logger.Debug("recurseInsertGbCamOrUnit err:", err) return false, err } tx.Commit() logger.Debug("SaveGb28181CamTree end!") s.AddDbChangeMsg(protomsg.DbAction_Update) return true, nil } func (s Gb28181Service) GetGb28181VssTable() VssTable { var vd gbModels.VssDev var du gbModels.VssDomainUnit var vc gbModels.VssChannel devices, _ := vd.FindAll() uM := du.FindAllMap() gbcM := vc.FindAllMap() var gbcModel models.Camera gbCams, _ := gbcModel.FindCamerasByType(models.TYPE_GB28181_CAMERA, "") var vssTable VssTable vssTable.Vd = devices vssTable.Du = uM vssTable.Vc = gbcM vssTable.GbCam = gbCams return vssTable } func recurseInsertGbCamOrUnit(tx *gorm.DB, menus []GbTreeMenu, uM map[string]gbModels.VssDomainUnit, cM map[string]gbModels.VssChannel, uIdMap map[string]gbDevAndArea, parentId string, cc map[string]models.Camera) error { for _, u := range menus { if u.Type == "menu" { uIdMap[u.Id] = gbDevAndArea{ PublicId: u.Id, ParentId: parentId, } gbArea := models.Area{ Id: u.Id, Name: u.Name, Parentid: parentId, Type: models.TYPE_GB28181_TREE, } if _, ok := uIdMap[parentId]; !ok { gbArea.Parentid = "0" } //递归得到parentids parentIds := "" GetPidsByRecursion(&uIdMap, gbArea.Parentid, &parentIds) gbArea.Parentids = parentIds if u.Name == "" { gbArea.Name = u.Id } var areaE models.Area rows, _ := areaE.SelectbyId(gbArea.Id) logger.Debug("recurseInsertGbCamOrUnit areaE.SelectById rows:", rows) if rows > 0 { gbArea.Alias = areaE.Alias } if err := tx.Table("area").Create(&gbArea).Error; err != nil { return err } if err := recurseInsertGbCamOrUnit(tx, u.Children, uM, cM, uIdMap, u.Id, cc); err != nil { logger.Debug("recurseInsertGbCamOrUnit err:", err) return err } } else { if gbCam, ok := cM[u.Id]; ok { //摄像机 cameraE := models.Camera{ Id: gbCam.PublicID, Name: gbCam.Name, Ip: gbCam.IP, Port: gbCam.Port, Rtsp: gbCam.RealRtspUrl, Addr: gbCam.Name, Alias: gbCam.Name, //别名默认取国标摄像机的名称 Longitude: float32(gbCam.Longitude), Latitude: float32(gbCam.Latitude), Type: models.TYPE_GB28181_CAMERA, //国标摄像机 Floor: models.Default_Layer, } if stc, sin := cc[cameraE.Id]; sin { cameraE.RunType = stc.RunType //保留之前配置的运行状态 cameraE.RunServerId = stc.RunServerId } else { cameraE.RunType = models.TYPE_RUNTYPE_VIDEO } if err := tx.Table("cameras").Create(&cameraE).Error; err != nil { return err } //关联摄像机和目录树 if err := tx.Table("camera_area").Create(&models.CameraArea{Cameraid: gbCam.PublicID, Areaid: parentId}).Error; err != nil { return err } } } } return nil } //递归获取国标树的摄像机数量 func recurseGbMenuCount(menus []GbTreeMenu, count *int) { if menus != nil && len(menus) > 0 { for _, u := range menus { if u.Type == "camera" { *count++ } else { recurseGbMenuCount(u.Children, count) } } } } //刷新国标树和设备 func (s Gb28181Service) RefreshById(id string) (bool, []GbTreeMenu) { if b, _ := s.UpdateGb28181Data(); b { data := s.GetGbCurrentTree() return true, data } return false, []GbTreeMenu{} } //刷新国标树和设备 func (s Gb28181Service) RefreshAllChannel() (bool, []GbTreeMenu) { if b, _ := s.UpdateGb28181Data(); b { data := s.GetGbCameras() return true, data } return false, []GbTreeMenu{} } //删除国标 func (s Gb28181Service) Delete() bool { var err error tx := models.GetDB().Begin() defer func() { if err != nil && tx != nil { tx.Rollback() } }() if err = tx.Exec("delete from area where type=1").Error; err != nil { return false } if err = tx.Exec("delete from cameras where type=1").Error; err != nil { return false } if err = tx.Exec("delete from camera_area where areaId in (select id from area where type=1)").Error; err != nil { return false } tx.Commit() s.AddDbChangeMsg(protomsg.DbAction_Update) return false } //摄像机表有更新 func (s Gb28181Service) AddDbChangeMsg(action protomsg.DbAction) { dbMsg := protomsg.DbChangeMessage{ Table: protomsg.TableChanged_T_Camera, Action: action, } pb, _ := json.Marshal(dbMsg) s.bk.Publish("gb28181-service", pb) //cameraPolygon有更新 pMsg := protomsg.DbChangeMessage{ Table: protomsg.TableChanged_T_CameraPolygon, Action: action, } ppm, _ := json.Marshal(pMsg) s.bk.Publish("gb28181-service", ppm) }