package controllers import ( "encoding/json" "errors" "sort" "strings" cc "vamicro/camera-common/models" "vamicro/config" "vamicro/extend/util" service2 "vamicro/saas-service/service" util2 "vamicro/saas-service/util" "vamicro/scene-service/models" "vamicro/scene-service/service" "vamicro/scene-service/vo" "basic.com/pubsub/protomsg.git" "basic.com/valib/bhomeclient.git" "basic.com/valib/bhomedbapi.git" "basic.com/valib/go-aiot.git/aiotProto/aiot" "basic.com/valib/logger.git" "github.com/jinzhu/gorm" ) type SyncDelBySaasReq struct { Ids []string `json:"ids"` Typ int `json:"typ"` Force bool `json:"force"` } const ( typeSyncDel_Camera = 1 typeSyncDel_Rule = 2 typeSyncDel_Polygon = 3 typeSyncDel_Time = 4 ) // @Summary 从saas删除已下发的摄像机、场景、区域或时间信息 // @Description 从saas删除已下发的摄像机、场景、区域或时间信息 // @Produce json // @Tags saas下发管理 // @Success 200 {string} json "{"code":200, success:true, msg:"", data:""}" // @Failure 500 {string} json "{"code":500, success:false, msg:"",data:""}" // @Router /data/api-v/camera/rule/syncDelBySaas [post] func (crc CameraRuleController) SyncDelBySaas(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var reqBody SyncDelBySaasReq if err := c.BindJSON(&reqBody); err != nil { return &bhomeclient.Reply{Msg: err.Error()} } switch reqBody.Typ { case typeSyncDel_Camera: if len(reqBody.Ids) != 1 { return &bhomeclient.Reply{Msg: "删除摄像机参数有误"} } var camApi bhomedbapi.CameraApi if !camApi.CameraDelete(reqBody.Ids[0]) { return &bhomeclient.Reply{Msg: "删除摄像机失败"} } case typeSyncDel_Rule: if len(reqBody.Ids) != 1 { return &bhomeclient.Reply{Msg: "删除场景参数有误"} } sv := service.CameraRuleService{ Broker: h.Bk, } if !sv.DeleteByGroup(reqBody.Ids[0]) { return &bhomeclient.Reply{Msg: "删除场景失败"} } case typeSyncDel_Polygon: sv := service.NewCameraPolygonService(h.Bk) if !sv.DeleteByIds(reqBody.Ids) { return &bhomeclient.Reply{Msg: "删除摄像机区域失败"} } case typeSyncDel_Time: if len(reqBody.Ids) != 1 { return &bhomeclient.Reply{Msg: "删除时间参数有误"} } sv := service.TimeService{Bk: h.Bk} if db, _ := sv.DeleteById(reqBody.Ids[0], reqBody.Force); !db { return &bhomeclient.Reply{Msg: "删除时间失败"} } default: return &bhomeclient.Reply{Msg: "invalid sync del typ"} } crc.notifyAll(h.Bk, reqBody.Ids, protomsg.DbAction_Delete) _, _ = service2.DoBusReq("/data/api-v/saas/syncCamera", config.Server.AnalyServerId, aiot.RequestMethod_Post, aiot.RequestContentType_ApplicationJson, map[string]interface{}{}) return &bhomeclient.Reply{Success: true, Msg: "同步删除成功"} } type CalculateReq struct { Cams []cc.Camera `json:"cams"` ClusterId string `json:"clusterId"` Sors []protomsg.Sensor `json:"sors"` Polygons []vo.CameraPolygonVo `json:"polygons"` Times []models.CameraTimerule `json:"times"` Rules []vo.GroupRuleVo `json:"rules"` Areas []cc.Area `json:"areas"` CamAndArea []cc.CameraArea `json:"camAndArea"` } type CameraAndArea struct { CameraId string `json:"cameraId"` AreaId string `json:"areaId"` } type SyncCameraAndArea struct { Cams []cc.Camera `json:"cams"` Areas []cc.Area `json:"areas"` CamAndArea []cc.CameraArea `json:"camAndArea"` } // @Summary 从saas下发摄像机及场景信息等 // @Description 从saas下发摄像机及场景信息等 // @Produce json // @Tags saas下发管理 // @Success 200 {string} json "{"code":200, success:true, msg:"", data:""}" // @Failure 500 {string} json "{"code":500, success:false, msg:"",data:""}" // @Router /data/api-v/camera/rule/dispatch [post] func (crc CameraRuleController) Dispatch(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { logger.Debug("dispatch-begin") var reqBody CalculateReq if err := c.BindJSON(&reqBody); err != nil { logger.Error("BindJSON err:", err) return &bhomeclient.Reply{Msg: err.Error()} } lock, err := service2.SetGlobalLock(util2.CameraRuleDispatch) defer service2.DelGlobalLock(util2.CameraRuleDispatch) if err != nil { logger.Error("fail to SetGlobalLock:", err) return &bhomeclient.Reply{Msg: err.Error()} } if !lock { err = errors.New("上锁失败,锁已存在,请稍后重试") logger.Error("fail to SetGlobalLock:", err) return &bhomeclient.Reply{Msg: err.Error()} } tx := models.GetDB().Begin() defer func() { if err != nil && tx != nil { logger.Error("dispatch Rollback err:", err) tx.Rollback() } }() //1.处理时间 for _, t := range reqBody.Times { var tr models.CameraTimerule rows, _ := tr.SelectById(t.Id) if rows == 0 { if err = tx.Table(tr.TableName()).Save(&models.CameraTimerule{ Id: t.Id, Name: t.Name, TimeRule: t.TimeRule, }).Error; err != nil { logger.Error("Save CameraTimerule err:", err) return &bhomeclient.Reply{Msg: err.Error()} } } else { tr.Id = t.Id tr.Name = t.Name tr.TimeRule = t.TimeRule if err = tx.Table(tr.TableName()).Save(&tr).Error; err != nil { logger.Error("Save CameraTimerule err:", err) return &bhomeclient.Reply{Msg: err.Error()} } } } //2.处理区域 for idx, _ := range reqBody.Polygons { if err = savePgn(&reqBody.Polygons[idx], tx); err != nil { logger.Error("savePgn err:", err) return &bhomeclient.Reply{Msg: err.Error()} } } //3.处理场景 for _, r := range reqBody.Rules { tmpData, _ := json.Marshal(r) logger.Debugf("dispatch-data tmpData=%v", string(tmpData)) var linkCameras []string cM := make(map[string]string) for _, v := range r.Rules { if v.CameraId != "" { if _, ok := cM[v.CameraId]; !ok { cM[v.CameraId] = v.CameraId } } } for _, v := range cM { linkCameras = append(linkCameras, v) } sort.Strings(linkCameras) dbCamIdStr := strings.Join(linkCameras, ",") var tmp models.CameraRuleGroup r1, _ := tmp.SelectById(r.Id) logger.Debugf("dispatch-data id=%v r1=%v, SceneName=%v", r.Id, r1, r.SceneName) if r1 == 0 { crg := models.CameraRuleGroup{ Id: r.Id, GroupText: r.GroupText, SetType: r.SetType, AlarmLevel: r.AlarmLevel, TemplateId: r.TemplateId, TemplateRule: "", TimeRuleId: r.TimeRuleId, SceneName: r.SceneName, Desc: r.Desc, Enable: true, VoiceId: r.VoiceId, } if err = tx.Table(crg.TableName()).Create(&crg).Error; err != nil { logger.Error("create crg err:", err) return &bhomeclient.Reply{Msg: err.Error()} } for sort, baseRule := range r.Rules { rga := models.CameraRuleGroupArg{ Id: baseRule.Id, } rga.CameraRuleBase = models.CameraRuleBase{ CameraId: baseRule.CameraId, SdkId: baseRule.SdkId, PolygonId: baseRule.PolygonId, RuleWithPre: baseRule.RuleWithPre, IsSaveAnyhow: baseRule.IsSaveAnyhow, Sort: sort, } setB, _ := json.Marshal(baseRule.SdkSet) rga.SdkSet = string(setB) rga.GroupId = crg.Id logger.Debugf("dispatch-data groupId=%v", crg.Id) if err = tx.Exec("insert into "+rga.TableName()+"(id,camera_id,sdk_id,polygon_id,sdk_set,rule_with_pre,is_save_anyhow,group_id,sort) values(?,?,?,?,?,?,?,?,?)", rga.Id, rga.CameraId, rga.SdkId, rga.PolygonId, rga.SdkSet, rga.RuleWithPre, rga.IsSaveAnyhow, rga.GroupId, rga.Sort).Error; err != nil { logger.Error("insert baseRule err:", err) return &bhomeclient.Reply{Msg: err.Error()} } } if len(linkCameras) > 1 { ctl := models.CameraTaskLink{ CameraIds: dbCamIdStr, LinkTaskId: r.Id, } if err = tx.Table(ctl.TableName()).Create(&ctl).Error; err != nil { logger.Error("CameraTaskLink Create failed:", err) return &bhomeclient.Reply{Msg: err.Error()} } } } else { if err = tx.Exec("delete from "+models.CameraRuleGroupArg{}.TableName()+" where group_id=?", r.Id).Error; err != nil { logger.Error("delete by groupId err:", err) return &bhomeclient.Reply{Msg: err.Error()} } if err = tx.Exec("update "+models.CameraRuleGroup{}.TableName()+" set template_id=?,time_rule_id=?,scene_name=?,desc=?,alarm_level=?,group_text=?,voiceId=? where id=?", r.TemplateId, r.TimeRuleId, r.SceneName, r.Desc, r.AlarmLevel, r.GroupText, r.VoiceId, r.Id).Error; err != nil { logger.Error("update crg err:", err) return &bhomeclient.Reply{Msg: err.Error()} } if len(linkCameras) > 1 { if err = tx.Exec("delete from "+models.CameraTaskLink{}.TableName()+" where link_task_id=?", r.Id).Error; err != nil { logger.Error("delete by groupId err:", err) return &bhomeclient.Reply{Msg: err.Error()} } ctl := models.CameraTaskLink{ CameraIds: dbCamIdStr, LinkTaskId: r.Id, } if err = tx.Table(ctl.TableName()).Create(&ctl).Error; err != nil { logger.Error("CameraTaskLink Create failed:", err) return &bhomeclient.Reply{Msg: err.Error()} } } for sort, baseRule := range r.Rules { rga := models.CameraRuleGroupArg{ Id: baseRule.Id, } rga.CameraRuleBase = models.CameraRuleBase{ CameraId: baseRule.CameraId, SdkId: baseRule.SdkId, PolygonId: baseRule.PolygonId, RuleWithPre: baseRule.RuleWithPre, IsSaveAnyhow: baseRule.IsSaveAnyhow, Sort: sort, } setB, _ := json.Marshal(baseRule.SdkSet) rga.SdkSet = string(setB) rga.GroupId = r.Id if err = tx.Exec("insert into "+rga.TableName()+"(id,camera_id,sdk_id,polygon_id,sdk_set,rule_with_pre,is_save_anyhow,group_id,sort) values(?,?,?,?,?,?,?,?,?)", rga.Id, rga.CameraId, rga.SdkId, rga.PolygonId, rga.SdkSet, rga.RuleWithPre, rga.IsSaveAnyhow, rga.GroupId, rga.Sort).Error; err != nil { logger.Error("insert crga err:", err) return &bhomeclient.Reply{Msg: err.Error()} } } } } //4.处理摄像机和目录树 var camApi bhomedbapi.CameraApi var gbcApi bhomedbapi.Gb28181Api var b bool sca := SyncCameraAndArea{ Cams: reqBody.Cams, Areas: reqBody.Areas, CamAndArea: reqBody.CamAndArea, } body := util.Struct2Map(sca) for _, cam := range reqBody.Cams { if cam.Type == cc.TYPE_GB28181_CAMERA { b = gbcApi.SaveNotExistOrUpdate(body) break } else { b = camApi.SaveNotExistOrUpdate(body) break } } //if b = camApi.SaveNotExistOrUpdate(body); !b { if !b { err = errors.New("save dispatch cam err") logger.Error("SaveNotExistOrUpdate err:", err) return &bhomeclient.Reply{Msg: err.Error()} } tx.Commit() logger.Debug("dispatch-end") var updIds []string for _, c := range reqBody.Cams { updIds = append(updIds, c.Id) } crc.notifyAll(h.Bk, updIds, protomsg.DbAction_Update) _, _ = service2.DoBusReq("/data/api-v/saas/syncCamera", config.Server.AnalyServerId, aiot.RequestMethod_Post, aiot.RequestContentType_ApplicationJson, map[string]interface{}{}) return &bhomeclient.Reply{Success: true, Msg: "dispatch success"} } func savePgn(cPolygon *vo.CameraPolygonVo, tx *gorm.DB) error { var model models.CameraPolygon var chIdArr []string for _, line := range cPolygon.Line { if line.Name != models.CAMERAPOLYGON_AREA_ALL { chIdArr = append(chIdArr, line.Id) model.Id = line.Id model.Name = line.Name model.CameraId = cPolygon.CameraId lineBytes, err := json.Marshal(line.Location) if err != nil { continue } model.Polygon = string(lineBytes) model.Type = models.TYPE_LINE if err := savePgnByTx(model, tx); err != nil { return err } } } for _, rect := range cPolygon.Rect { if rect.Name != models.CAMERAPOLYGON_AREA_ALL { chIdArr = append(chIdArr, rect.Id) rectBytes, _ := json.Marshal(rect.Location) model = models.CameraPolygon{ Id: rect.Id, Name: rect.Name, Polygon: string(rectBytes), CameraId: cPolygon.CameraId, } //判断矩形内是否有箭头 arrows := service.GetArrowInPolygon(cPolygon.Arrow, rect.Location) //多边形内部的箭头 if len(arrows) > 0 { arrowBytes, _ := json.Marshal(arrows[0]) //取第一个箭头 model.DirectionLine = string(arrowBytes) } model.Type = models.TYPE_RECT if err := savePgnByTx(model, tx); err != nil { return err } } } for _, pg := range cPolygon.Polygon { if pg.Name != models.CAMERAPOLYGON_AREA_ALL { chIdArr = append(chIdArr, pg.Id) pgbytes, _ := json.Marshal(pg.Location) model = models.CameraPolygon{ Id: pg.Id, Name: pg.Name, Polygon: string(pgbytes), CameraId: cPolygon.CameraId, } arrows := service.GetArrowInPolygon(cPolygon.Arrow, pg.Location) //多边形内部的箭头 if len(arrows) > 0 { arrowBytes, _ := json.Marshal(arrows[0]) //多边形内只能有一个箭头 model.DirectionLine = string(arrowBytes) } model.Type = models.TYPE_POLYGON if err := savePgnByTx(model, tx); err != nil { return err } } } return nil } func savePgnByTx(pgn models.CameraPolygon, tx *gorm.DB) error { var tmp models.CameraPolygon result := tx.Table(tmp.TableName()).Where("id=?", pgn.Id).First(&tmp) if result.RowsAffected == 0 { if err := tx.Table(tmp.TableName()).Create(&pgn).Error; err != nil { return err } } else { if err := tx.Table(tmp.TableName()).Save(&pgn).Error; err != nil { return err } } return nil } func (crc CameraRuleController) notifyAll(bk bhomeclient.Broker, cams []string, action protomsg.DbAction) { for _, cId := range cams { //摄像机信息更新需要通知具体变化的id crc.addDbChangeMsg(bk, protomsg.TableChanged_T_Camera, cId, action, "") } crc.addDbChangeMsg(bk, protomsg.TableChanged_T_CameraRule, "", action, "") crc.addDbChangeMsg(bk, protomsg.TableChanged_T_CameraPolygon, "", action, "") crc.addDbChangeMsg(bk, protomsg.TableChanged_T_TimeRule, "", action, "") }