package controllers import ( "bytes" "database/sql" "encoding/json" "fmt" "image" "path/filepath" // "fmt" // "io/ioutil" // "os" // "path/filepath" // "unsafe" "strconv" "strings" "vamicro/camera-common/models" "vamicro/camera-common/service" "vamicro/camera-common/vo" "vamicro/camera-service/cache" csv "vamicro/camera-service/service" service2 "vamicro/saas-service/service" "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" //"vamicro/camera-common/service/uniquelCoordinate" commonModel "vamicro/api-gateway/models" "vamicro/config" "vamicro/extend/util" scs "vamicro/scene-service/controllers" ) type CameraController struct { } // @Summary 添加摄像机 // @Description "传入 区域的id(areaid)和摄像机名字(name) 必须, 其他参数可以在摄像机配置点击保存进行添加" // @Accept json // @Produce json // @Tags camera // @Param cameraStruct body vo.CameraEditVo true "struct of camera;the areaid of area's id and name of camera;must need" // @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/add [post] func (cc CameraController) CameraAdd(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var camVo vo.CameraEditVo if err := c.BindJSON(&camVo); err != nil { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } sv := service.CameraService{} b, camE, err := sv.CameraAdd(camVo) if b { cc.addDbChangeMsg(h.Bk, protomsg.TableChanged_T_Camera, camVo.Id, protomsg.DbAction_Insert, "") cc.addDbChangeMsg(h.Bk, protomsg.TableChanged_T_CameraPolygon, "", protomsg.DbAction_Insert, "") _, _ = service2.DoBusReq("/data/api-v/saas/syncCamera", config.Server.AnalyServerId, aiot.RequestMethod_Post, aiot.RequestContentType_ApplicationJson, map[string]interface{}{}) return &bhomeclient.Reply{Success: true, Data: camE} } else { return &bhomeclient.Reply{Success: false, Msg: err.Error()} } } // @Summary 更新摄像机 // @Description "用于更新摄像机操作" // @Accept json // @Produce json // @Tags camera // @Param cam body vo.CameraEditVo true "id:摄像机id default:cid0 (string), areaid:摄像机关联区域id default:1 (int), name:摄像机名字 default:Testname(string) 必填; 其他参数可配 " // @Success 200 {string} json "{"code":200, success:true, msg:"请求处理成功", data:"修改后的摄像机信息"}" // @Failure 500 {string} json "{"code":500, success:false msg:"null",data:"错误信息内容"}" // @Router /data/api-v/camera/update [put] func (cc CameraController) CameraUpdate(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var camVo vo.CameraEditVo err := c.BindJSON(&camVo) if err != nil { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } logger.Debug("update sensors:", camVo.Sensors) sv := service.CameraService{} if b, err := sv.CameraUpdate(camVo); b { cc.addDbChangeMsg(h.Bk, protomsg.TableChanged_T_Camera, camVo.Id, 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, Data: camVo.Copy2Camera()} } else { return &bhomeclient.Reply{Success: false, Msg: err.Error()} } } // @Summary "删除摄像机" // @Description "根据摄像机id删除摄像机" // @Produce json // @Tags camera // @Param cid query string true "摄像机id example: cid0" // @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/del [delete] func (cc CameraController) CameraDel(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var cam models.Camera cid := c.Query("id") logger.Debug("CameraDel.id:", cid) if cid == "" { return &bhomeclient.Reply{Msg: "参数有误,摄像机id不能为空"} } rows, _ := cam.Delete(cid) if rows == 0 { return &bhomeclient.Reply{Success: true, Msg: "记录不存在"} } pMsg := protomsg.DbChangeMessage{ //需要重新计算算力占用情况 Table: protomsg.TableChanged_T_Camera, Action: protomsg.DbAction_Delete, } pb, _ := json.Marshal(pMsg) h.Bk.Publish(csv.ProcName, pb) _, _ = 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: "删除成功"} } // @Summary 显示摄像机 // @Description "显示摄像机" // @Produce json // @Tags camera // @Param id path string true "摄像机id" // @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/show [get] func (cc CameraController) CameraSel(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var cam models.Camera cid := c.Query("id") rows, err := cam.SelectById(cid) if err != nil { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } if rows == 0 { return &bhomeclient.Reply{Success: false, Msg: "没有记录"} } m := util.Struct2Map(cam) var sor models.Sensor sensors, _ := sor.FindByCameraId(cid) if sensors != nil { m["sensors"] = sensors } else { m["sensors"] = []models.Sensor{} } //摄像机分辨率 dRe0 := models.Resolution{ Width: 0, Height: 0, } dRe1 := models.Resolution{ Width: 1920, Height: 1080, } dRe2 := models.Resolution{ Width: 2688, Height: 1520, } m["resolutions"] = []models.Resolution{dRe0, dRe1, dRe2} //获取督查任务 tasks := models.GetTasks() //处理摄像机的状态 //var crApi bhomedbapi.CameraRuleApi if cam.RunType == models.TYPE_RUNTYPE_POLL || cam.RunType == models.TYPE_RUNTYPE_REALTIME { //if crApi.ExistRunningTask(cam.Id) { if taskInfo, ok := tasks[cam.Id]; ok && taskInfo != nil && len(taskInfo) > 0 { if cam.IsRunning { m["status"] = models.Camera_Status_Doing } else { m["status"] = models.Camera_Status_Wait } } else { m["status"] = models.Camera_Status_NoRule } } else { m["status"] = models.Camera_Status_Err } if cam.RunServerId != "" { if cam.RunServerId == config.Server.AnalyServerId { lc, e := cache.GetServerInfo() if e == nil { m["runServerName"] = lc.ServerName } } else { //属于其他服务器 var cluApi bhomedbapi.ClusterApi flag, info := cluApi.FindCluster() if flag && info.ClusterId != "" && len(info.Nodes) > 0 { for _, n := range info.Nodes { if cam.RunServerId == n.NodeId { m["runServerName"] = n.NodeName break } } } } } //_, _ = service2.DoBusReq("/data/api-v/saas/syncCamera", config.Server.AnalyServerId, aiot.RequestMethod_Post, aiot.RequestContentType_ApplicationJson, map[string]interface{}{}) return &bhomeclient.Reply{Success: true, Data: m} } // @Summary 获取所有摄像机列表及信息 // @Description "获取所有摄像机列表及信息" // @Produce json // @Tags camera // @Param cameraName query string false "摄像机名称" // @Param runType query string false "0:全部,1:分析,2:监控,3:联动" // @Param cameraId query string false "摄像机id" // @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/showAll [get] func (cc CameraController) GetAllCameras(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { cameraName := c.Query("cameraName") cameraType, _ := strconv.Atoi(c.Query("runType")) cameraId := c.Query("cameraId") areaId := c.Query("areaId") var cam models.Camera lkMap := make(map[string]string) linkWhere := "" if cameraType == 3 { //查联动 var crApi bhomedbapi.CameraRuleApi lb, lkList := crApi.FindAllCameraLink() if !lb { return &bhomeclient.Reply{Msg: "查询联动配置失败"} } if len(lkList) == 0 { return &bhomeclient.Reply{Success: true, Data: []struct{}{}} } for _, lc := range lkList { cArr := strings.Split(lc.CameraIds, ",") for _, lcId := range cArr { if _, ok := lkMap[lcId]; !ok { lkMap[lcId] = lcId } } } for k := range lkMap { linkWhere += "'" + k + "'," } linkWhere = strings.TrimRight(linkWhere, ",") } cams, err := cam.FindAllByServer(config.Server.AnalyServerId, cameraName, cameraType, cameraId, areaId, linkWhere) if err != nil { return &bhomeclient.Reply{Success: false, Msg: err.Error()} } return &bhomeclient.Reply{Success: true, Data: cams} } // @Summary 获取运行类型获取摄像机列表 // @Description 获取运行类型获取摄像机列表 // @Produce json // @Tags camera // @Param runType query int true "0:查轮询,1:查实时" // @Param cameraName query string false "查询条件" // @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/getCamerasByRunType [get] func (cc CameraController) GetCamerasByRunType(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { runTypeStr := c.Query("runType") cameraName := c.Query("cameraName") logger.Debug("runType:", runTypeStr) logger.Debug("cameraName:", cameraName) runType, err := strconv.Atoi(runTypeStr) if err != nil || (runType != 0 && runType != 1) { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } sv := service.CameraService{} list, err := sv.GetCamerasByRunType(runType, cameraName) if err != nil { return &bhomeclient.Reply{Success: false, Msg: err.Error()} } else { return &bhomeclient.Reply{Success: true, Data: list} } } // @Summary 切换摄像机运行实时或轮询的开关 // @Description 切换摄像机运行实时或轮询的开关 // @Produce json // @Tags camera // @Param cameraId formData string true "摄像机id" // @Param runEnable formData bool true "开启:true,关闭:false" // @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/updateRunEnable [post] func (cc CameraController) UpdateRunEnable(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { cameraId := c.PostForm("cameraId") enableStr := c.PostForm("runEnable") runEnable, _ := strconv.ParseBool(enableStr) if cameraId == "" { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } sv := service.CameraService{} if sv.UpdateRunEnable(cameraId, runEnable) { cc.addDbChangeMsg(h.Bk, protomsg.TableChanged_T_Camera, cameraId, 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: "更新成功"} } else { return &bhomeclient.Reply{Success: false, Msg: "更新失败"} } } // @Summary 摄像机轮询和实时状态切换 // @Description 摄像机轮询和实时状态切换 // @Produce json // @Tags camera // @Param changeRunBody body vo.CameraChangeRunVo true "参数结构体,0:实时切轮询,1:轮询切实时" // @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/changeRunType [post] func (cc CameraController) ChangeRunType(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var ccrVo vo.CameraChangeRunVo if err := c.BindJSON(&ccrVo); err != nil { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } sv := service.CameraService{} if sv.ChangeRunType(ccrVo) { //cIds := strings.Join(ccrVo.CameraIds, ",") //cc.addDbChangeMsg(h.Bk, protomsg.TableChanged_T_Camera, cIds, 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: "更新成功"} } else { return &bhomeclient.Reply{Success: false, Msg: "更新失败"} } } // @Summary 摄像机is_running状态切换 // @Description 摄像机is_running状态切换 // @Produce json // @Tags camera // @Param cameraId formData string true "摄像机id" // @Param is_running formData bool true "解码中:true,停止解码:false" // @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/updateIsRunningState [post] func (cc CameraController) UpdateIsRunningState(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { cameraId := c.PostForm("cameraId") isRunningStr := c.PostForm("isRunning") isRunning, _ := strconv.ParseBool(isRunningStr) if cameraId == "" { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } sv := service.CameraService{} if sv.UpdateIsRunningState(cameraId, isRunning) { _, _ = 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: "更新成功"} } else { return &bhomeclient.Reply{Success: false, Msg: "更新失败"} } } type IsRunningArg struct { CameraIds []string `json:"cameraIds"` } func (cc CameraController) UpdateIsRunningAll(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var reqBody IsRunningArg c.BindJSON(&reqBody) logger.Debug("UpdateIsRunningAll cameraId:", reqBody.CameraIds) sv := service.CameraService{} if sv.UpdateIsRunningAll(reqBody.CameraIds) { _, _ = 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: "更新成功"} } else { return &bhomeclient.Reply{Success: false, Msg: "更新失败"} } } const ( File_Img_Id_Pre = "img_" File_Video_Id_Pre = "video_" File_Audio_Id_Pre = "audio_" ) // @Summary 更新摄像机快照 // @Description 更新摄像机快照 // @Produce json // @Tags camera // @Param cameraId formData string true "摄像机id" // @Param snapshot formData string true "快照地址" // @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/updateSnapshotUrl [post] func (cc CameraController) UpdateSnapshot(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { cameraId := c.Query("cameraId") logger.Debug("cameraId:", cameraId) if cameraId == "" { return &bhomeclient.Reply{Msg: "参数有误"} } if strings.HasPrefix(cameraId, File_Video_Id_Pre) || strings.HasPrefix(cameraId, File_Img_Id_Pre) || strings.HasPrefix(cameraId, File_Audio_Id_Pre) { var fileApi bhomedbapi.FileAnalysisApi b, d := fileApi.Show(cameraId) if b { var file protomsg.FileAnalysis bytes, _ := json.Marshal(d) err := json.Unmarshal(bytes, &file) if err == nil { return &bhomeclient.Reply{Success: true, Data: map[string]string{ "cameraId": cameraId, "snapshotUrl": file.SnapshotUrl, }} } else { return &bhomeclient.Reply{Msg: "更新失败"} } } else { return &bhomeclient.Reply{Msg: "更新失败"} } } sv := service.CameraService{} flag, camInfo := sv.GetById(cameraId) if !flag { return &bhomeclient.Reply{Msg: "获取摄像机失败"} } ////////////////////////////////////////////////// /* 将capture的图片保存在本地 因为网页请求时有5s超时,在此期间很可能拿不到图片 */ // const baseMapDir = "./cameraBaseMapDir/" // baseMapFile := baseMapDir + cameraId // rep := &bhomeclient.Reply{Msg: "未查找到预存的图片"} // if _, base64Str, _ := csv.UpdateCapture(camInfo.Type, camInfo.Rtsp, "", camInfo.Name); len(base64Str) > 0 { // rep = &bhomeclient.Reply{ // Success: true, // Msg: "从本地[cameraBaseMapDir]获取图片base64", // Data: map[string]string{ // "cameraId": cameraId, // "snapshotUrl": "", // "base64": base64Str, // }, // } // _, err := os.Stat(baseMapDir) // if os.IsNotExist(err) { // if err := os.MkdirAll(baseMapDir, 0755); err != nil { // logger.Debug("======>> 未获取到图片文件夹") // fmt.Println("======>> 未获取到图片文件夹") // } // logger.Debug("======>> create basemap directory") // fmt.Println("======>> create basemap directory") // } // tmp := (*[2]uintptr)(unsafe.Pointer(&base64Str)) // tmp2 := [3]uintptr{tmp[0], tmp[1], tmp[1]} // b64 := *(*[]byte)(unsafe.Pointer(&tmp2)) // if err := ioutil.WriteFile(baseMapFile, b64, 0644); err != nil { // logger.Debug("======>> WriteFile Image BaseMap Failed") // fmt.Println("======>> WriteFile Image BaseMap Failed") // } // } else { // // 首先查找是否存在此照片 // found := false // filepath.Walk(baseMapDir, func(path string, info os.FileInfo, err error) error { // if err != nil { // return err // } // if !info.IsDir() && info.Name() == cameraId { // found = true // return nil // } // return nil // }) // if found { // if image, err := ioutil.ReadFile(baseMapFile); err == nil { // logger.Debug("======>> 获取图片,发送回去") // fmt.Println("======>> 获取图片,发送回去") // rep = &bhomeclient.Reply{ // Success: true, // Msg: "从本地[cameraBaseMapDir]获取图片base64", // Data: map[string]string{ // "cameraId": cameraId, // "snapshotUrl": "", // "base64": *(*string)(unsafe.Pointer(&image)), // }, // } // } // } // } // return rep /* 将capture的图片保存在本地 因为网页请求时有5s超时,在此期间很可能拿不到图片 */ ////////////////////////////////////////////////// var sysApi bhomedbapi.SysSetApi sb, sysconf := sysApi.GetServerInfo() if !sb || sysconf.WebPicIp == "" { return &bhomeclient.Reply{Msg: "未获取到图片服务器ip"} } weedfsUri := "http://" + sysconf.WebPicIp + ":" + strconv.Itoa(int(sysconf.WebPicPort)) + "/submit?collection=" + sysconf.ServerId + "-persistent" filename, base64Str, err := csv.UpdateCapture(camInfo.Type, camInfo.Rtsp, weedfsUri, camInfo.Name) if err != nil { logger.Debug("UpdateSnapshotUrl.err:", err) if base64Str != "" { //上传到图片服务器失败 return &bhomeclient.Reply{Msg: "上传失败,返回base64", Data: map[string]string{ "cameraId": cameraId, "snapshotUrl": "", "base64": base64Str, }} } else { return &bhomeclient.Reply{Msg: "更新失败,原因:" + err.Error()} } } if sv.UpdateSnapshot(cameraId, filename) { return &bhomeclient.Reply{Success: true, Msg: "更新成功", Data: map[string]string{ "cameraId": cameraId, "snapshotUrl": filename, "base64": base64Str, }} } else { return &bhomeclient.Reply{Success: false, Msg: "更新失败"} } } // @Summary 更新摄像机快照 // @Description 更新摄像机快照 // @Produce json // @Tags camera // @Param id formData string true "摄像机id" // @Param type formData int true "摄像机类型" // @Param rtsp formData string true "摄像机rtsp地址" // @Param name formData string true "摄像机名称" // @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/updateSnapshotSaaS [get] func (cc CameraController) UpdateSnapshotSaaS(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { cameraId := c.Query("id") name := c.Query("name") typeStr := c.Query("type") rtsp := c.Query("rtsp") logger.Debug("cameraId: ", cameraId, "name: ", name, "type: ", typeStr, "rtsp: ", rtsp) if cameraId == "" || rtsp == "" || name == "" { return &bhomeclient.Reply{Msg: "参数有误"} } camType, err := strconv.Atoi(typeStr) if err != nil || (camType != 0 && camType != 1) { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } if strings.HasPrefix(cameraId, File_Video_Id_Pre) || strings.HasPrefix(cameraId, File_Img_Id_Pre) || strings.HasPrefix(cameraId, File_Audio_Id_Pre) { var fileApi bhomedbapi.FileAnalysisApi b, d := fileApi.Show(cameraId) if b { var file protomsg.FileAnalysis bytes, _ := json.Marshal(d) err := json.Unmarshal(bytes, &file) if err == nil { return &bhomeclient.Reply{Success: true, Data: map[string]string{ "cameraId": cameraId, "snapshotUrl": file.SnapshotUrl, }} } else { return &bhomeclient.Reply{Msg: "更新失败"} } } else { return &bhomeclient.Reply{Msg: "更新失败"} } } sv := service.CameraService{} var sysApi bhomedbapi.SysSetApi sb, sysconf := sysApi.GetServerInfo() if !sb || sysconf.WebPicIp == "" { return &bhomeclient.Reply{Msg: "未获取到图片服务器ip"} } weedfsUri := "http://" + sysconf.WebPicIp + ":" + strconv.Itoa(int(sysconf.WebPicPort)) + "/submit?collection=" + sysconf.ServerId + "-persistent" filename, base64Str, err := csv.UpdateCapture(camType, rtsp, weedfsUri, name) if err != nil { logger.Debug("UpdateSnapshotUrl.err:", err) if base64Str != "" { //上传到图片服务器失败 return &bhomeclient.Reply{Success: true, Msg: "上传失败,返回base64", Data: map[string]string{ "cameraId": cameraId, "snapshotUrl": "", "base64": base64Str, }} } else { return &bhomeclient.Reply{Msg: "更新失败,原因:" + err.Error()} } } if sv.UpdateSnapshot(cameraId, filename) { return &bhomeclient.Reply{Success: true, Msg: "更新成功", Data: map[string]string{ "cameraId": cameraId, "snapshotUrl": filename, "base64": base64Str, }} } else { return &bhomeclient.Reply{Success: true, Msg: "更新失败,返回base64", Data: map[string]string{ "cameraId": cameraId, "snapshotUrl": filename, "base64": base64Str, }} } } // 拖拽到其他组织 // 需要 当前camid , 以及修改后的areaid // 直接使用camera update api interface. // @Summary 将摄像机挂到指定的目录树下 // @Description 将摄像机挂到指定的目录树下 // @Produce json // @Tags camera // @Param cameraId formData string true "摄像机id" // @Param areaId formData string true "目录区域id" // @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/updateCameraArea [post] func (cc CameraController) UpdateCameraArea(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { cameraId := c.PostForm("cameraId") areaId := c.PostForm("areaId") if cameraId == "" || areaId == "" { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } var caE models.CameraArea if caE.UpdateArea(cameraId, areaId) { return &bhomeclient.Reply{Success: true, Msg: "更新成功"} } else { return &bhomeclient.Reply{Success: false, Msg: "更新失败"} } } // @Summary 删除某一个目录树下的指定摄像机 // @Description 删除某一个目录树下的指定摄像机 // @Produce json // @Tags camera // @Param cameraId path string true "摄像机id" // @Param areaId path string true "指定目录区域id" // @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/cameraAreaDel [get] func (cc CameraController) CameraAreaDel(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { //cameraId := c.Param("cameraId") //areaId := c.Param("areaId") //logger.Debug(cameraId) //logger.Debug(areaId) return nil } // @Summary 在地图上获取摄像机列表 // @Description 在地图上获取摄像机列表 // @Produce json // @Tags camera // @Param quryArg body vo.CameraQueryVo true "摄像机列表查询" // @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/findOnMap [post] func (cc CameraController) FindOnMap(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var searchArg vo.CameraQueryVo err := c.BindJSON(&searchArg) if err != nil { return &bhomeclient.Reply{Msg: "参数有误"} } logger.Debug("isOnMap:", searchArg.IsOnMap) logger.Debug("floorStr:", searchArg.Floor) logger.Debug("cameraName:", searchArg.CameraName) var cam models.Camera cams, err := cam.FindBy(searchArg.IsOnMap, searchArg.Floor, searchArg.CameraName) if err != nil { return &bhomeclient.Reply{Msg: "查询失败"} } return &bhomeclient.Reply{Success: true, Data: cams} } // @Summary 更新摄像机地图位置 // @Description 更新摄像机地图位置 // @Produce json // @Tags camera // @Param posArg body vo.CameraPosVo true "摄像机位置更新参数" // @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/updatePos [post] func (cc CameraController) UpdatePos(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var arg vo.CameraPosVo err := c.BindJSON(&arg) if err != nil || arg.Id == "" { return &bhomeclient.Reply{Msg: "参数有误"} } var cam models.Camera if cam.UpdatePos(arg.Id, arg.Floor, arg.Longitude, arg.Latitude) { return &bhomeclient.Reply{Success: true, Msg: "更新成功"} } else { return &bhomeclient.Reply{Msg: "更新失败"} } } // @Summary 获取集群中各节点的摄像机 // @Description 获取集群中各节点的摄像机 // @Produce json // @Tags camera // @Param searchType query int true "查询类型(0:全部,1:分析摄像机,2:监控摄像机, 3:联动摄像机)" // @Param cameraName query string false "摄像机名称" // @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/nodeCamera [get] func (cc CameraController) NodeCamera(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { searchType, _ := strconv.Atoi(c.Query("searchType")) camName := c.Query("cameraName") lkMap := make(map[string]string) linkWhere := "" if searchType == 3 { //查联动 var crApi bhomedbapi.CameraRuleApi lb, lkList := crApi.FindAllCameraLink() if !lb { return &bhomeclient.Reply{Msg: "查询联动配置失败"} } if len(lkList) == 0 { return &bhomeclient.Reply{Success: true, Data: []struct{}{}} } for _, lc := range lkList { cArr := strings.Split(lc.CameraIds, ",") for _, lcId := range cArr { if _, ok := lkMap[lcId]; !ok { lkMap[lcId] = lcId } } } for k := range lkMap { linkWhere += "'" + k + "'," } linkWhere = strings.TrimRight(linkWhere, ",") } var camE models.Camera allCams, _ := camE.FindAllByServer("", camName, searchType, "", "", linkWhere) result := make([]models.TreeMenu, 0) var clusterApi bhomedbapi.ClusterApi b, ci := clusterApi.FindCluster() if b { if ci.Nodes != nil && len(ci.Nodes) > 0 { for _, n := range ci.Nodes { result = append(result, models.TreeMenu{ Id: n.NodeId, Name: n.NodeName, Type: "MENU", Areanodes: getCamsByNodeId(allCams, n.NodeId), }) } } } return &bhomeclient.Reply{Success: true, Data: result} } func getCamsByNodeId(cams []models.Camera, nodeId string) []models.TreeMenu { arr := make([]models.TreeMenu, 0) if cams != nil { var camRuleApi bhomedbapi.CameraRuleApi for _, c := range cams { if c.RunServerId == nodeId { isRunnig := false isAI := false camera := models.Camera{} rows, e := camera.SelectById(c.Id) if rows > 0 && e == nil { isRunnig = camera.IsRunning isAI = camRuleApi.ExistRunningTask(c.Id) && (camera.RunType == models.TYPE_RUNTYPE_POLL || camera.RunType == models.TYPE_RUNTYPE_REALTIME) } arr = append(arr, models.TreeMenu{ Id: c.Id, Type: "4", Name: c.Name, IsAI: isAI, //是否AI摄像机 IsRunning: isRunnig, Rtsp: c.Rtsp, CameraType: -1, }) } } } return arr } // @Summary 获取摄像机的坐标标定信息 // @Description 获取摄像机的坐标标定信息 // @Produce json // @Tags camera // @Param cameraId query string true "摄像机id" // @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/coord [get] func (cc CameraController) Coord(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { cameraId := c.Query("cameraId") if cameraId == "" { return &bhomeclient.Reply{Msg: "参数有误"} } logger.Debug("coord cameraId:", cameraId) var camE models.Camera rows, err := camE.SelectById(cameraId) if err == nil && rows > 0 { var snapShotUrl = "" if camE.SnapshotUrl == "" { var sysApi bhomedbapi.SysSetApi sb, sysconf := sysApi.GetServerInfo() if !sb || sysconf.WebPicIp == "" { return &bhomeclient.Reply{Msg: "未获取到图片服务器ip"} } weedfsUri := "http://" + sysconf.WebPicIp + ":" + strconv.Itoa(int(sysconf.WebPicPort)) + "/submit?collection=" + sysconf.ServerId + "-persistent" //没有底图需要先刷新底图 snapUrl, _, err := csv.UpdateCapture(camE.Type, camE.Rtsp, weedfsUri, camE.Name) if err != nil { return &bhomeclient.Reply{Msg: err.Error()} } snapShotUrl = snapUrl } else { snapShotUrl = camE.SnapshotUrl } if !strings.HasPrefix(snapShotUrl, "http://") { snapShotUrl = "http://" + snapShotUrl } result := vo.CoordTransShow{ Coords: make([]vo.CoordTrans, 0), PanoramaCoords: make([]vo.CPoint, 0), } if camE.CoordTransform == "" { return &bhomeclient.Reply{Success: true, Data: result} } else { var coords []vo.CoordTrans err := json.Unmarshal([]byte(camE.CoordTransform), &coords) if err != nil { logger.Debug("unmarshal CoordTransform err:", err) return &bhomeclient.Reply{Msg: "坐标转换失败"} } result.Coords = coords } if len(result.Coords) == 0 { result.PanoramaCoords = make([]vo.CPoint, 0) return &bhomeclient.Reply{Success: true, Data: result} } bts, dE := util.DownLoad(snapShotUrl) if dE != nil { return &bhomeclient.Reply{Msg: "获取摄像机底图失败"} } reader := bytes.NewReader(bts) im, _, err := image.DecodeConfig(reader) if err != nil { return &bhomeclient.Reply{Msg: "获取底图分辨率宽高失败"} } w := im.Width h := im.Height logger.Debug("coord w:", w, "h", h) /*args, e := json.Marshal(map[string]interface{}{ "coordTrans": result.Coords, "w": w, "h": h, }) if e != nil { return &bhomeclient.Reply{Msg:e.Error()} } panoCoordStr := uniquelCoordinate.TransCoord(string(args)) if panoCoordStr != "" { logger.Debug("panoCoordStr:", panoCoordStr) var cresult vo.CCoordResult err = json.Unmarshal([]byte(panoCoordStr), &cresult) if err != nil { logger.Debug("将panoCoordStr 转化为CCoordResult失败,err:", err) result.PanoramaCoords = make([]vo.CPoint, 0) } else { result.PanoramaCoords = cresult.Result } }*/ return &bhomeclient.Reply{Success: true, Data: result} } else { return &bhomeclient.Reply{Msg: "摄像机查询失败"} } } // @Summary 更新摄像机的坐标标定信息 // @Description 更新摄像机的坐标标定信息 // @Produce json // @Tags camera // @Param reqBody body vo.CoordSetVo true "摄像机坐标转换参数" // @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/updateCoord [post] func (cc CameraController) UpdateCoord(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var reqBody vo.CoordSetVo err := c.BindJSON(&reqBody) if err != nil || reqBody.CameraId == "" { return &bhomeclient.Reply{Msg: "参数有误"} } //有时候会出现x0和y0相同,但是x1和y1不一样的bug m := make(map[string]vo.CoordTrans) newList := make([]vo.CoordTrans, 0) for _, ct := range reqBody.Coords { k := strconv.Itoa(ct.X0) + ":" + strconv.Itoa(ct.Y0) if _, exist := m[k]; !exist { newList = append(newList, ct) m[k] = ct } } reqBody.Coords = newList //去除重复的 bts, err := json.Marshal(reqBody.Coords) if err != nil { return &bhomeclient.Reply{Msg: "坐标转换失败"} } var camE models.Camera if camE.UpdateCoordTrans(reqBody.CameraId, string(bts)) { return &bhomeclient.Reply{Success: true, Msg: "更新成功"} } else { return &bhomeclient.Reply{Msg: "更新失败"} } } func (cc CameraController) addDbChangeMsg(bk bhomeclient.Broker, tChanged protomsg.TableChanged, id string, action protomsg.DbAction, info string) { dbMsg := protomsg.DbChangeMessage{ Table: tChanged, Id: id, Action: action, Info: info, } pb, _ := json.Marshal(dbMsg) bk.Publish(csv.ProcName, pb) } // @Summary 获取要同步的摄像机信息数据 // @Description 获取要同步的摄像机信息数据 // @Produce json // @Tags camera // @Param reqBody body vo.CoordSetVo true "" // @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/GetSyncCameraData [post] func (cc CameraController) GetSyncCameraData(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { // 获取设备相继信息 var camS service.CameraService camera, err := camS.GetSyncCamera() if err != nil { return &bhomeclient.Reply{Success: false, Msg: "获取摄像机信息失败", Data: camera} } return &bhomeclient.Reply{Success: true, Msg: "获取成功", Data: camera} } // @Summary 获取要同步的摄像机传感器信息数据 // @Description 获取要同步的摄像机传感器信息数据 // @Produce json // @Tags camera // @Param reqBody body vo.CoordSetVo true "" // @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/GetSyncSensorData [post] func (cc CameraController) GetSyncSensorData(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { // 获取设备相继信息 var camS service.CameraService camera, err := camS.GetSyncSensor() if err != nil { return &bhomeclient.Reply{Success: false, Msg: "获取摄像机传感器信息失败", Data: camera} } return &bhomeclient.Reply{Success: true, Msg: "获取成功", Data: camera} } func (cc CameraController) SaveNotExistOrUpdate(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { var reqBody scs.SyncCameraAndArea if e := c.BindJSON(&reqBody); e != nil { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } var err error tx := models.GetDB().Begin() defer func() { if err != nil && tx != nil { logger.Error("SaveNotExistOrUpdate rollback err:", err) tx.Rollback() } }() sv := service.CameraService{} for _, cam := range reqBody.Cams { if err = sv.SaveNotExistOrUpdate(tx, cam); err != nil { logger.Error("SaveNotExistOrUpdate err:", err) return &bhomeclient.Reply{Msg: err.Error()} } } if err = sv.SaveOrUpdateAreas(tx, reqBody.Areas, reqBody.CamAndArea); err != nil { logger.Error("SaveOrUpdateAreas err:", err) return &bhomeclient.Reply{Msg: err.Error()} } tx.Commit() cc.addDbChangeMsg(h.Bk, protomsg.TableChanged_T_Camera, "", protomsg.DbAction_Update, "") cc.addDbChangeMsg(h.Bk, protomsg.TableChanged_T_CameraPolygon, "", 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: "保存成功"} } /** * 获取抓拍记录 */ func (cc CameraController) GetRecord(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { //绑定json和结构体 info := models.RecordReq{} if err := c.BindJSON(&info); err != nil { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } page := info.Page pageSize := info.PageSize idsStr := info.Ids TaskIds := info.TaskIds TaskName := info.TaskName videoIdStr := info.VideoIds Warning := info.Warning filter := "zh_desc_class != '' " //根据id获取记录 var ids []string if len(idsStr) > 0 { for _, tmp := range idsStr { id, _ := strconv.ParseInt(tmp, 10, 64) if id > 0 { ids = append(ids, tmp) } } filter += fmt.Sprintf(" and %s in [%s]", "id", strings.Join(ids, ",")) } //根据视频id查询 var videoIds []string if len(videoIdStr) > 0 { for _, tmp := range videoIdStr { if len(tmp) > 0 { videoIds = append(videoIds, tmp) } } //根据id查询视频id var vids []int64 cameras, _ := models.GetCameraIds(videoIds) for _, camera := range cameras { if len(camera.Id) > 0 { vids = append(vids, camera.VideoId) } } idStr := make([]string, len(vids)) for i, id := range vids { idStr[i] = strconv.FormatInt(id, 10) } filter += fmt.Sprintf(" and %s in [%s]", "video_point_id", strings.Join(idStr, ",")) } //根据任务查询 if len(TaskIds) > 0 { filter += fmt.Sprintf(" and array_contains(task_id, %d)", TaskIds[0]) } //根据任务名称 if len(TaskName) > 0 { quotedNames := make([]string, len(TaskName)) for i, name := range TaskName { quotedNames[i] = "'" + name + "'" // 每个元素加单引号 } filter += fmt.Sprintf(" and %s in [%s]", "task_name", strings.Join(quotedNames, ",")) } else { if Warning > 0 { return &bhomeclient.Reply{Success: true, Msg: "获取成功", Data: nil} } } //是否预警 if Warning > 0 { filter += fmt.Sprintf(" and is_waning == %d", Warning) } //filter += " ORDER BY detect_time DESC" if len(filter) > 0 { logger.Error("filter err:", filter) } result, err := models.GetWithPage("smartobject", int64(page), int64(pageSize), filter) // 通用响应 if err != nil { if err == sql.ErrNoRows { return &bhomeclient.Reply{Success: false, Msg: "数据为空"} } else { return &bhomeclient.Reply{Success: false, Msg: "获取列表失败"} } } //组织数据 //重新组织数据 basePath := commonModel.GetBasePath() tmpAllDate := make(map[string]interface{}) tmpDate := make(map[string][]interface{}) for _, v := range result.Items { sources := make(map[string]interface{}, 0) temp := models.StaticRecord{ Id: v.Id, TaskId: v.TaskId, RuleId: v.RuleId, EventLevelId: v.EventLevelId, VideoPointId: v.VideoPointId, DetectId: v.DetectId, ImagePath: v.ImagePath, VideoPath: v.VideoPath, DetectTime: v.DetectTime, IsWarning: v.IsWarning, DetectNum: v.DetectNum, TaskName: v.TaskName, ZhDescClass: v.ZhDescClass, EventLevelName: v.EventLevelName, KnowledgeId: v.KnowledgeId, Suggestion: v.Suggestion, RiskDescription: v.RiskDescription, IsDesc: v.IsDesc, PicMaxUrl: []string{v.ImagePath}, PicSrcUrl: []string{v.ImagePath}, PicWH: models.PicWidHei{PicH: 720, PicW: 1280}, VideoUrl: v.VideoPath, AnalyServerName: "智能服务节点", Content: v.CameraName, PicDate: v.PicDate, LikeDate: v.LikeDate, VideoName: v.CameraName, CameraAddr: v.CameraName, } //任务名称 items, _ := models.GetTaskByIds(v.TaskId) temp.TaskNames = items //视频内容 // items4, _ := models.GetVideoById(v.VideoPointId) // temp.VideoName = items4.Name // temp.CameraAddr = items4.Addr //检查内容 items2, _ := models.GetCheckByIds(v.DetectId) temp.CheckNames = items2 //规则内容 items3, _ := models.GetRuleByIds(v.RuleId) temp.RuleNames = items3 //事件 items5, _ := models.GetEventByIds(v.EventLevelId) temp.EventLevels = items5 //知识库 items6, _ := models.GetKnowledgeDocumentByIds(v.KnowledgeId) // 知识库路径 var KnowledgePath = "/txt/zs/" for i := range items6 { filePath := filepath.Join(basePath + KnowledgePath + items6[i].Title) newPath := filepath.ToSlash(filePath) items6[i].FileUrl = newPath } temp.KnowledgeDocuments = items6 sources["list"] = []interface{}{ temp, } sources["activeObject"] = temp tmpDate["datalist"] = append(tmpDate["datalist"], sources) } tmpAllDate["datalist"] = tmpDate["datalist"] var pageRes = &models.PaginatedResult2{ Pagination: result.Pagination, Items: tmpAllDate, } return &bhomeclient.Reply{Success: true, Msg: "获取成功", Data: pageRes} } /** *获取督查任务 */ func (cc CameraController) GetTasks(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { //绑定json和结构体 info := models.Video{} if err := c.BindJSON(&info); err != nil { return &bhomeclient.Reply{Success: false, Msg: "参数有误"} } var tasks []models.Task if len(info.VideoIds) > 0 { tasks, _ = models.GetListTask(info.VideoIds) } return &bhomeclient.Reply{Success: true, Msg: "获取成功", Data: tasks} } // 获取所有 func (cc CameraController) GetAllTasks(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply { //绑定json和结构体 var tasks []models.TaskAggregate tasks, _ = models.GetAllTask() return &bhomeclient.Reply{Success: true, Msg: "获取成功", Data: tasks} }