package service
|
|
import (
|
"basic.com/pubsub/protomsg.git"
|
"basic.com/valib/bhomedbapi.git"
|
"basic.com/valib/logger.git"
|
"encoding/json"
|
"errors"
|
"fmt"
|
"github.com/jinzhu/gorm"
|
"github.com/satori/go.uuid"
|
"strconv"
|
"strings"
|
"vamicro/camera-common/models"
|
"vamicro/camera-common/pub"
|
"vamicro/camera-common/vo"
|
"vamicro/config"
|
"vamicro/extend/util"
|
)
|
|
type CameraService struct {
|
}
|
|
func (sv CameraService) CameraAdd(camVo vo.CameraEditVo) (bool, models.Camera, error) {
|
cam := camVo.Copy2Camera()
|
//2020-11-04 验证rtsp地址在本机是
|
b, _ := IsRtspExist(camVo.Rtsp)
|
if b {
|
return false, cam, errors.New("rtsp地址冲突,本机已存在此rtsp摄像机")
|
}
|
|
if strings.HasPrefix(cam.Rtsp, "rtsp://") {
|
encodeRtsp, err := util.EncodeRTSPPassword(cam.Rtsp)
|
if err != nil {
|
return false, cam, errors.New("rtsp地址格式错误")
|
} else {
|
fmt.Println("encodertstp,", encodeRtsp)
|
cam.Rtsp = encodeRtsp
|
}
|
}
|
|
var sysApi bhomedbapi.SysSetApi
|
flag, sysconf := sysApi.GetServerInfo()
|
var realMax = 16
|
if flag && sysconf.RealMax > 0 {
|
realMax = int(sysconf.RealMax)
|
}
|
|
var err error
|
tx := models.GetDB().Begin()
|
defer func() {
|
if err != nil && tx != nil {
|
tx.Rollback()
|
}
|
}()
|
cam.Type = models.TYPE_LOCAL_CAMERA // 本地摄像机
|
var areaE models.Area
|
if camVo.AreaId != "0" {
|
if _, err = areaE.SelectbyId(camVo.AreaId); err != nil {
|
return false, cam, err
|
}
|
}
|
cam.Id = uuid.NewV4().String()
|
cam.RunServerId = config.Server.AnalyServerId
|
if camVo.RunType != models.TYPE_RUNTYPE_VIDEO && camVo.RunType != models.TYPE_RUNTYPE_POLL && camVo.RunType != models.TYPE_RUNTYPE_REALTIME {
|
cam.RunType = models.TYPE_RUNTYPE_VIDEO
|
} else {
|
cam.RunType = camVo.RunType
|
}
|
if cam.RunType == models.TYPE_RUNTYPE_REALTIME { //实时需要判断实时数量
|
realList, e := cam.GetCamerasByRunType(models.TYPE_RUNTYPE_REALTIME, "")
|
if e != nil || len(realList) >= realMax {
|
return false, cam, e
|
}
|
}
|
|
cam.RunEnable = true
|
cam.Floor = models.Default_Layer
|
|
//添加摄像机的时候不应该指定RunServerId,在哪台服务器上配了任务,RunServerId就是对应的那台服务器
|
if err = tx.Table("cameras").Create(&cam).Error; err != nil {
|
return false, cam, err
|
}
|
|
if err = tx.Table("camera_area").Create(&models.CameraArea{Cameraid: cam.Id, Areaid: camVo.AreaId}).Error; err != nil {
|
return false, cam, err
|
}
|
|
//处理传感器
|
if len(camVo.Sensors) > 0 {
|
for _, sor := range camVo.Sensors {
|
var sorE models.Sensor
|
exist := sorE.Exist(sor.Ip, sor.Port)
|
sorId := ""
|
if exist {
|
sorId = sorE.Id
|
} else {
|
sor.Id = uuid.NewV4().String()
|
if err = tx.Table(sor.TableName()).Create(&sor).Error; err != nil {
|
return false, cam, err
|
}
|
sorId = sor.Id
|
}
|
if err = tx.Exec("insert into camera_sensor(camera_id, sensor_id) select '" + cam.Id + "','" + sorId + "' where not exists (select 1 from camera_sensor where camera_id='" + cam.Id + "' and sensor_id='" + sorId + "')").Error; err != nil {
|
return false, cam, err
|
}
|
}
|
}
|
tx.Commit()
|
camBytes, _ := json.Marshal(cam)
|
sv.addDbChangeMsg(protomsg.TableChanged_T_Camera, cam.Id, protomsg.DbAction_Insert, string(camBytes))
|
dbMsg := protomsg.DbChangeMessage{
|
Table: protomsg.TableChanged_T_CameraPolygon,
|
Id: cam.Id,
|
Action: protomsg.DbAction_Insert,
|
Info: string(""),
|
}
|
pub.AddDbMessage(&dbMsg)
|
return true, cam, nil
|
}
|
|
// 判断rtsp在本机的摄像机列表中是否重复,集群内可以重复
|
func IsRtspExist(rtsp string) (bool, []models.Camera) {
|
if !config.Server.RtspUnique {
|
return false, nil
|
}
|
var camE models.Camera
|
cams, _ := camE.FindByRtsp(rtsp)
|
if cams != nil {
|
found := false
|
var sameArr []models.Camera
|
for _, c := range cams {
|
if c.RunServerId == config.Server.AnalyServerId {
|
found = true
|
sameArr = append(sameArr, c)
|
}
|
}
|
return found, sameArr
|
}
|
return false, nil
|
}
|
|
func (sv CameraService) GetById(cameraId string) (bool, models.Camera) {
|
var camE models.Camera
|
rows, err := camE.SelectById(cameraId)
|
if err == nil && rows > 0 {
|
return true, camE
|
} else {
|
return false, models.Camera{}
|
}
|
}
|
|
func (sv CameraService) CameraUpdate(camVo vo.CameraEditVo) (bool, error) {
|
cam := camVo.Copy2Camera()
|
|
b, sameArr := IsRtspExist(cam.Rtsp)
|
if b {
|
if len(sameArr) > 1 || (len(sameArr) == 1 && sameArr[0].Id != cam.Id) {
|
return false, errors.New("rtsp地址冲突,本机已存在此rtsp摄像机")
|
}
|
}
|
|
if strings.HasPrefix(cam.Rtsp, "rtsp://") {
|
encodeRtsp, err := util.EncodeRTSPPassword(cam.Rtsp)
|
if err != nil {
|
return false, errors.New("rtsp地址格式错误")
|
} else {
|
fmt.Println("encodertstp,", encodeRtsp)
|
|
cam.Rtsp = encodeRtsp
|
}
|
}
|
|
var sysApi bhomedbapi.SysSetApi
|
flag, sysconf := sysApi.GetServerInfo()
|
var realMax = 16
|
if flag && sysconf.RealMax > 0 {
|
realMax = int(sysconf.RealMax)
|
}
|
|
var camTmp models.Camera
|
rows, err := camTmp.SelectById(cam.Id)
|
if err != nil || rows == 0 {
|
return false, errors.New("查询摄像机失败")
|
}
|
|
cam.Floor = camTmp.Floor
|
if camTmp.RunServerId == "" { //未设置过run_server_id,此种情况是国标摄像机第一次保存,会选择目标服务器的id
|
cam.RunServerId = config.Server.AnalyServerId //此摄像机归属到本台分析服务器
|
//if cam.RunServerId == "" {
|
// return false
|
//}
|
} else {
|
cam.RunServerId = camTmp.RunServerId //虽然国标摄像机集群内共享,但是更新时不会修改归属
|
}
|
|
//过滤非法数据
|
if cam.RunType != models.TYPE_RUNTYPE_VIDEO && cam.RunType != models.TYPE_RUNTYPE_POLL && cam.RunType != models.TYPE_RUNTYPE_REALTIME {
|
cam.RunType = models.TYPE_RUNTYPE_VIDEO
|
}
|
if cam.RunType == models.TYPE_RUNTYPE_REALTIME {
|
if camTmp.RunType != models.TYPE_RUNTYPE_REALTIME { //由非实时到实时的切换时,需要判断当前的实时数量
|
realList, e := cam.GetCamerasByRunType(models.TYPE_RUNTYPE_REALTIME, "")
|
if e != nil || len(realList) >= realMax {
|
return false, errors.New("实时数量已达到上限")
|
}
|
}
|
}
|
//处理传感器
|
var camSensor models.CameraSensor
|
if !camSensor.DeleteByCamId(camVo.Id) {
|
logger.Debug("cameraSensor deleteByCameraId fail")
|
return false, errors.New("传感器删除失败")
|
}
|
|
if camVo.Sensors != nil && len(camVo.Sensors) > 0 {
|
for _, sor := range camVo.Sensors {
|
var sorE models.Sensor
|
exist := sorE.Exist(sor.Ip, sor.Port)
|
sorId := ""
|
if exist {
|
sorId = sorE.Id
|
if err = models.GetDB().Table(sor.TableName()).Where("id=?", sorId).Update(&sor).Error; err != nil {
|
return false, err
|
}
|
} else {
|
sor.Id = uuid.NewV4().String()
|
if err = models.GetDB().Table(sor.TableName()).Create(&sor).Error; err != nil {
|
return false, err
|
}
|
sorId = sor.Id
|
}
|
if err = models.GetDB().Exec("insert into camera_sensor(camera_id, sensor_id) select '" + cam.Id + "','" + sorId + "' where not exists (select 1 from camera_sensor where camera_id='" + camVo.Id + "' and sensor_id='" + sorId + "')").Error; err != nil {
|
return false, err
|
}
|
}
|
}
|
|
cam.IsRunning = camTmp.IsRunning
|
cam.Type = camTmp.Type
|
|
err = cam.Update()
|
if err != nil {
|
return false, err
|
}
|
|
camBytes, _ := json.Marshal(cam)
|
sv.addDbChangeMsg(protomsg.TableChanged_T_Camera, cam.Id, protomsg.DbAction_Update, string(camBytes))
|
return true, nil
|
}
|
|
func (sv CameraService) GetCamerasByRunType(runType int, cameraName string) (cams []vo.CamSensorVo, err error) {
|
//指定当前机器为过滤条件
|
var cameraE models.Camera
|
list, err := cameraE.GetCamerasByRunType(runType, cameraName)
|
logger.Debug("GetCamerasByRunType len(list):", len(list), " err:", err)
|
if err != nil {
|
return nil, err
|
}
|
var crApi bhomedbapi.CameraRuleApi
|
var sensorE models.Sensor
|
for _, cam := range list { //判断每一个摄像机是否有可运行的任务和规则
|
if crApi.ExistRunningTask(cam.Id) {
|
sensors, _ := sensorE.FindByCameraId(cam.Id)
|
var camSor vo.CamSensorVo
|
camSor.Camera = cam
|
if sensors != nil {
|
camSor.Sensors = sensors
|
} else {
|
camSor.Sensors = []models.Sensor{}
|
}
|
|
cams = append(cams, camSor)
|
}
|
}
|
return cams, nil
|
}
|
|
func (sv CameraService) UpdateIsRunningState(id string, isRunning bool) bool {
|
var cameraE models.Camera
|
return cameraE.UpdateIsRunningState(id, isRunning)
|
|
}
|
|
func (sv CameraService) UpdateIsRunningAll(camIds []string) bool {
|
var cameraE models.Camera
|
return cameraE.UpdateIsRunningAll(camIds)
|
}
|
|
func (sv CameraService) UpdateRunEnable(cameraId string, runEnable bool) bool {
|
var cameraE models.Camera
|
return cameraE.UpdateRunEnable(cameraId, runEnable)
|
}
|
|
// 1.判断本地摄像机的实时数量
|
// 2.判断是否安装有国标,以及国标实时摄像机的数量
|
func (sv CameraService) ChangeRunType(ccrVo vo.CameraChangeRunVo) bool {
|
logger.Debug("ChangeRunType params:", ccrVo)
|
var sysApi bhomedbapi.SysSetApi
|
flag, sysconf := sysApi.GetServerInfo()
|
var realMax = 16
|
if flag && sysconf.RealMax > 0 {
|
realMax = int(sysconf.RealMax)
|
}
|
|
var err error
|
tx := models.GetDB().Begin()
|
defer func() {
|
if err != nil && tx != nil {
|
tx.Rollback()
|
}
|
}()
|
|
for _, cameraId := range ccrVo.CameraIds {
|
var camE models.Camera
|
rows, e := camE.SelectById(cameraId)
|
if e == nil && rows > 0 {
|
if ccrVo.RunType == models.TYPE_RUNTYPE_REALTIME {
|
//非实时向实时切换
|
if camE.RunType != models.TYPE_RUNTYPE_REALTIME {
|
realList, e := camE.GetCamerasByRunType(models.TYPE_RUNTYPE_REALTIME, "")
|
if e != nil || len(realList) >= realMax {
|
logger.Warn("realTime cameras limit " + strconv.Itoa(realMax))
|
return false
|
}
|
} else {
|
continue
|
}
|
}
|
|
sql := fmt.Sprintf("update cameras set run_type=%d, is_running=0 where id='%s'", ccrVo.RunType, cameraId)
|
if camE.RunServerId == "" {
|
sql = fmt.Sprintf("update cameras set run_type=%d, run_server_id='%s', is_running=0 where id='%s'", ccrVo.RunType, config.Server.AnalyServerId, cameraId)
|
}
|
|
logger.Debug(sql)
|
if err = tx.Exec(sql).Error; err != nil {
|
logger.Warn(err)
|
return false
|
}
|
|
} else {
|
logger.Warn("find camera by id failure, id:", cameraId, " err:", e, " row:", rows)
|
}
|
}
|
|
tx.Commit()
|
cIds := strings.Join(ccrVo.CameraIds, ",")
|
sv.addDbChangeMsg(protomsg.TableChanged_T_Camera, cIds, protomsg.DbAction_Update, "")
|
//var pollConfSv PollConfigService
|
//pollConfSv.ResetChannelCount()
|
return true
|
}
|
|
func (sv CameraService) UpdateSnapshot(cameraId string, snapshot string) bool {
|
var cameraE models.Camera
|
return cameraE.UpdateSnapshot(cameraId, snapshot)
|
}
|
|
// 通过摄像机id获取在哪台服务器上运行
|
func GetRunServerName(cameraId string) string {
|
var runServerName = ""
|
|
var camTmp models.Camera
|
rows, _ := camTmp.SelectById(cameraId)
|
if rows > 0 {
|
var syssetApi bhomedbapi.SysSetApi
|
fb, localConf := syssetApi.GetServerInfo()
|
if fb {
|
if camTmp.RunServerId == localConf.ServerId { //归属本台服务器
|
runServerName = localConf.ServerName
|
} else { //属于其他服务器
|
var clusterApi bhomedbapi.ClusterApi
|
flag, cInfo := clusterApi.FindCluster()
|
if flag {
|
if cInfo.Nodes != nil {
|
for _, n := range cInfo.Nodes {
|
if n.Id == camTmp.RunServerId {
|
runServerName = n.NodeName
|
break
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
return runServerName
|
}
|
|
func (sv CameraService) addDbChangeMsg(tChanged protomsg.TableChanged, id string, action protomsg.DbAction, info string) {
|
dbMsg := protomsg.DbChangeMessage{
|
Table: tChanged,
|
Id: id,
|
Action: action,
|
Info: info,
|
}
|
pub.AddDbMessage(&dbMsg)
|
}
|
|
// 获取摄像机数据
|
func (sv CameraService) GetSyncCamera() (vo.SyncCameraResult, error) {
|
res := vo.SyncCameraResult{}
|
// 摄像机信息
|
var camM models.Camera
|
camList, err := camM.FindAll()
|
if err != nil {
|
logger.Error("fail to find camera list", err)
|
return res, err
|
}
|
res.Cameras = camList
|
|
// 区域
|
var areaM models.Area
|
areaList, err := areaM.FindAll()
|
if err != nil {
|
logger.Error("fail to find area list", err)
|
return res, err
|
}
|
res.Area = areaList
|
|
// 摄像机关联区域
|
var camAreaM models.CameraArea
|
camAreaList, err := camAreaM.FindAll()
|
if err != nil {
|
logger.Error("fail to find camera area list", err)
|
return res, err
|
}
|
res.CameraArea = camAreaList
|
logger.Debug("camera", res)
|
return res, nil
|
}
|
|
// 获取同步传感器信息
|
func (sv CameraService) GetSyncSensor() (vo.SyncSensorResult, error) {
|
res := vo.SyncSensorResult{}
|
// 传感器
|
var sensorM models.Sensor
|
sensorList, err := sensorM.FindAll()
|
if err != nil {
|
logger.Error("fail to find sensor list", err)
|
return res, err
|
}
|
res.Sensor = sensorList
|
|
// 摄像机传感器
|
var csM models.CameraSensor
|
csList, err := csM.FindAll()
|
if err != nil {
|
logger.Error("fail to find camera sensor list", err)
|
return res, err
|
}
|
res.CameraSensor = csList
|
|
return res, nil
|
}
|
|
func (sv CameraService) SaveNotExistOrUpdate(tx *gorm.DB, cam models.Camera) error {
|
b, sameArr := IsRtspExist(cam.Rtsp)
|
if b {
|
if len(sameArr) > 1 || (len(sameArr) == 1 && sameArr[0].Id != cam.Id) {
|
return errors.New("rtsp地址冲突,本机已存在此rtsp摄像机")
|
}
|
}
|
cam.RunServerId = config.Server.AnalyServerId
|
|
var sysApi bhomedbapi.SysSetApi
|
flag, sysconf := sysApi.GetServerInfo()
|
var realMax = 16
|
if flag && sysconf.RealMax > 0 {
|
realMax = int(sysconf.RealMax)
|
}
|
|
var camTmp models.Camera
|
rows, _ := camTmp.SelectById(cam.Id)
|
if rows == 0 {
|
if err := tx.Table(cam.TableName()).Create(&cam).Error; err != nil {
|
return err
|
}
|
} else {
|
|
cam.Floor = camTmp.Floor
|
if camTmp.RunServerId == "" { //未设置过run_server_id,此种情况是国标摄像机第一次保存,会选择目标服务器的id
|
cam.RunServerId = config.Server.AnalyServerId //此摄像机归属到本台分析服务器
|
//if cam.RunServerId == "" {
|
// return false
|
//}
|
} else {
|
cam.RunServerId = camTmp.RunServerId //虽然国标摄像机集群内共享,但是更新时不会修改归属
|
}
|
|
//过滤非法数据
|
if cam.RunType != models.TYPE_RUNTYPE_VIDEO && cam.RunType != models.TYPE_RUNTYPE_POLL && cam.RunType != models.TYPE_RUNTYPE_REALTIME {
|
cam.RunType = models.TYPE_RUNTYPE_VIDEO
|
}
|
if cam.RunType == models.TYPE_RUNTYPE_REALTIME {
|
if camTmp.RunType != models.TYPE_RUNTYPE_REALTIME { //由非实时到实时的切换时,需要判断当前的实时数量
|
realList, e := cam.GetCamerasByRunType(models.TYPE_RUNTYPE_REALTIME, "")
|
if e != nil || len(realList) >= realMax {
|
return errors.New("实时数量已达到上限")
|
}
|
}
|
}
|
//处理传感器
|
//var camSensor models.CameraSensor
|
//if !camSensor.DeleteByCamId(cam.Id) {
|
// logger.Debug("cameraSensor deleteByCameraId fail")
|
// return errors.New("传感器删除失败")
|
//}
|
|
//if camVo.Sensors != nil && len(camVo.Sensors) > 0 {
|
// for _, sor := range camVo.Sensors {
|
// var sorE models.Sensor
|
// exist := sorE.Exist(sor.Ip, sor.Port)
|
// sorId := ""
|
// if exist {
|
// sorId = sorE.Id
|
// if err = models.GetDB().Table(sor.TableName()).Where("id=?", sorId).Update(&sor).Error; err != nil {
|
// return false, err
|
// }
|
// } else {
|
// sor.Id = uuid.NewV4().String()
|
// if err = models.GetDB().Table(sor.TableName()).Create(&sor).Error; err != nil {
|
// return false, err
|
// }
|
// sorId = sor.Id
|
// }
|
// if err = models.GetDB().Exec("insert into camera_sensor(camera_id, sensor_id) select '" + cam.Id + "','" + sorId + "' where not exists (select 1 from camera_sensor where camera_id='" + camVo.Id + "' and sensor_id='" + sorId + "')").Error; err != nil {
|
// return false, err
|
// }
|
// }
|
//}
|
|
cam.IsRunning = camTmp.IsRunning
|
cam.Type = camTmp.Type
|
|
if err := tx.Table(cam.TableName()).Save(&cam).Error; err != nil {
|
return err
|
}
|
}
|
|
return nil
|
}
|
|
func (sv CameraService) SaveOrUpdateAreas(tx *gorm.DB, areas []models.Area, cas []models.CameraArea) error {
|
for _, a := range areas {
|
tmp := a
|
var count int
|
if err := tx.Table(a.TableName()).Where("id=?", a.Id).Count(&count).Error; err != nil {
|
return err
|
}
|
if count == 0 {
|
if err := tx.Table(tmp.TableName()).Create(&tmp).Error; err != nil {
|
return err
|
}
|
} else {
|
if err := tx.Table(tmp.TableName()).Save(&tmp).Error; err != nil {
|
return err
|
}
|
}
|
}
|
for _, ca := range cas {
|
var count int
|
if err := tx.Table(ca.TableName()).Where("cameraId=? and areaId=?", ca.Cameraid, ca.Areaid).Count(&count).Error; err != nil {
|
return err
|
}
|
if count == 0 {
|
tmp := models.CameraArea{
|
Cameraid: ca.Cameraid,
|
Areaid: ca.Areaid,
|
}
|
if err := tx.Table(tmp.TableName()).Create(&tmp).Error; err != nil {
|
return err
|
}
|
}
|
}
|
return nil
|
}
|