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, "")
|
}
|