package main import ( "database/sql" "fmt" "net/http" "time" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) // getStringValue 获取sql.NullString的值 func getStringValue(ns sql.NullString) string { if ns.Valid { return ns.String } return "" } // getInt64Value 获取sql.NullInt64的值 func getInt64Value(ni sql.NullInt64) int64 { if ni.Valid { return ni.Int64 } return 0 } // getTimeValue 获取sql.NullTime的值 func getTimeValue(nt sql.NullTime) time.Time { if nt.Valid { return nt.Time } return time.Time{} } // CameraRequest 摄像头请求结构 type CameraRequest struct { Name string `json:"name" binding:"required"` IP string `json:"ip" binding:"required"` Username string `json:"username"` Password string `json:"password"` RTSPURL string `json:"rtsp_url" binding:"required"` Enabled bool `json:"enabled"` } // CameraResponse 摄像头响应结构 - 适配qsc_camera表 type CameraResponse struct { CameraID int `json:"camera_id"` IP string `json:"ip"` Port int `json:"port"` Username string `json:"username"` Password string `json:"password,omitempty"` URL string `json:"url"` CameraProduce string `json:"camera_produce"` CameraName string `json:"camera_name"` DeviceType string `json:"device_type"` UnitCode string `json:"unit_code"` NvrProduce string `json:"nvr_produce"` NvrPath string `json:"nvr_path"` PlayBack string `json:"play_back"` DelFlag string `json:"del_flag"` CreateBy string `json:"create_by"` CreateTime time.Time `json:"create_time"` UpdateBy string `json:"update_by"` UpdateTime time.Time `json:"update_time"` UserID int64 `json:"user_id"` DeptID int64 `json:"dept_id"` StreamStatus string `json:"stream_status"` } // HTTPAPIServerCameras 获取所有摄像头 func HTTPAPIServerCameras(c *gin.Context) { if !Storage.Server.DatabaseEnabled { c.JSON(http.StatusServiceUnavailable, gin.H{ "error": "Database is not enabled", }) return } cameras, err := Storage.dbManager.GetAllCameras() if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameras", "call": "GetAllCameras", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } // 转换为响应格式 var responses []CameraResponse for _, camera := range cameras { // 检查流状态 streamID := fmt.Sprintf("%d", camera.CameraID) streamStatus := "offline" if _, exists := Storage.Streams[streamID]; exists { if Storage.StreamChannelExist(streamID, "0") { streamStatus = "online" } } response := CameraResponse{ CameraID: camera.CameraID, IP: camera.IP, Port: camera.Port, Username: getStringValue(camera.Username), Password: getStringValue(camera.Password), URL: camera.URL, CameraProduce: getStringValue(camera.CameraProduce), CameraName: getStringValue(camera.CameraName), DeviceType: getStringValue(camera.DeviceType), UnitCode: getStringValue(camera.UnitCode), NvrProduce: getStringValue(camera.NvrProduce), NvrPath: getStringValue(camera.NvrPath), PlayBack: getStringValue(camera.PlayBack), DelFlag: camera.DelFlag, CreateBy: getStringValue(camera.CreateBy), CreateTime: getTimeValue(camera.CreateTime), UpdateBy: getStringValue(camera.UpdateBy), UpdateTime: getTimeValue(camera.UpdateTime), UserID: getInt64Value(camera.UserID), DeptID: getInt64Value(camera.DeptID), StreamStatus: streamStatus, } responses = append(responses, response) } c.JSON(http.StatusOK, gin.H{ "cameras": responses, "total": len(responses), }) } // HTTPAPIServerCamerasByUnitCode 根据unitcode获取摄像头列表 func HTTPAPIServerCamerasByUnitCode(c *gin.Context) { if !Storage.Server.DatabaseEnabled { c.JSON(http.StatusServiceUnavailable, gin.H{ "error": "Database is not enabled", }) return } unitCode := c.Param("unitcode") if unitCode == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "Unit code is required", }) return } cameras, err := Storage.dbManager.GetCamerasByUnitCode(unitCode) if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCamerasByUnitCode", "call": "GetCamerasByUnitCode", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } // 转换为响应格式 var responses []CameraResponse for _, camera := range cameras { // 检查流状态 streamID := fmt.Sprintf("%d", camera.CameraID) streamStatus := "offline" if _, exists := Storage.Streams[streamID]; exists { if Storage.StreamChannelExist(streamID, "0") { streamStatus = "online" } } response := CameraResponse{ CameraID: camera.CameraID, IP: camera.IP, Port: camera.Port, Username: getStringValue(camera.Username), Password: getStringValue(camera.Password), URL: camera.URL, CameraProduce: getStringValue(camera.CameraProduce), CameraName: getStringValue(camera.CameraName), DeviceType: getStringValue(camera.DeviceType), UnitCode: getStringValue(camera.UnitCode), NvrProduce: getStringValue(camera.NvrProduce), NvrPath: getStringValue(camera.NvrPath), PlayBack: getStringValue(camera.PlayBack), DelFlag: camera.DelFlag, CreateBy: getStringValue(camera.CreateBy), CreateTime: getTimeValue(camera.CreateTime), UpdateBy: getStringValue(camera.UpdateBy), UpdateTime: getTimeValue(camera.UpdateTime), UserID: getInt64Value(camera.UserID), DeptID: getInt64Value(camera.DeptID), StreamStatus: streamStatus, } responses = append(responses, response) } c.JSON(http.StatusOK, gin.H{ "cameras": responses, "total": len(responses), "unit_code": unitCode, }) } // HTTPAPIServerCameraAdd 添加新摄像头 func HTTPAPIServerCameraAdd(c *gin.Context) { if !Storage.Server.DatabaseEnabled { c.JSON(http.StatusServiceUnavailable, gin.H{ "error": "Database is not enabled", }) return } var req CameraRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), }) return } // 创建摄像头记录 - 适配qsc_camera表 camera := Camera{ IP: req.IP, Port: 554, // 默认RTSP端口 Username: sql.NullString{String: req.Username, Valid: req.Username != ""}, Password: sql.NullString{String: req.Password, Valid: req.Password != ""}, URL: req.RTSPURL, CameraName: sql.NullString{String: req.Name, Valid: true}, DeviceType: sql.NullString{String: "网络摄像头", Valid: true}, UnitCode: sql.NullString{String: "DEFAULT", Valid: true}, // 默认单位代码 DelFlag: "0", CreateBy: sql.NullString{String: "admin", Valid: true}, CreateTime: sql.NullTime{Time: time.Now(), Valid: true}, UpdateBy: sql.NullString{String: "admin", Valid: true}, UpdateTime: sql.NullTime{Time: time.Now(), Valid: true}, UserID: sql.NullInt64{Int64: 1, Valid: true}, DeptID: sql.NullInt64{Int64: 1, Valid: true}, } // 保存到数据库 err := Storage.dbManager.CreateCamera(&camera) if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameraAdd", "call": "CreateCamera", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } // 检查流是否已存在 streamID := fmt.Sprintf("%d", camera.CameraID) if _, exists := Storage.Streams[streamID]; exists { c.JSON(http.StatusConflict, gin.H{ "error": "Stream already exists", }) return } // 转换为流配置并添加到内存 stream := CameraToStream(camera) err = Storage.StreamAdd(streamID, stream) if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameraAdd", "call": "StreamAdd", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } c.JSON(http.StatusCreated, gin.H{ "message": "Camera added successfully", "camera_id": camera.CameraID, }) } // HTTPAPIServerCameraUpdate 更新摄像头 func HTTPAPIServerCameraUpdate(c *gin.Context) { if !Storage.Server.DatabaseEnabled { c.JSON(http.StatusServiceUnavailable, gin.H{ "error": "Database is not enabled", }) return } cameraID := c.Param("uuid") if cameraID == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "Camera ID is required", }) return } var req CameraRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), }) return } // 检查摄像头是否存在 existingCamera, err := Storage.dbManager.GetCameraByID(cameraID) if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameraUpdate", "call": "GetCameraByID", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } if existingCamera == nil { c.JSON(http.StatusNotFound, gin.H{ "error": "Camera not found", }) return } // 更新摄像头信息 - 适配qsc_camera表 updatedCamera := *existingCamera // 复制现有摄像头信息 updatedCamera.IP = req.IP updatedCamera.Username = sql.NullString{String: req.Username, Valid: req.Username != ""} updatedCamera.Password = sql.NullString{String: req.Password, Valid: req.Password != ""} updatedCamera.URL = req.RTSPURL updatedCamera.CameraName = sql.NullString{String: req.Name, Valid: true} updatedCamera.UpdateBy = sql.NullString{String: "admin", Valid: true} updatedCamera.UpdateTime = sql.NullTime{Time: time.Now(), Valid: true} // 更新数据库 err = Storage.dbManager.UpdateCamera(&updatedCamera) if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameraUpdate", "call": "UpdateCamera", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } // 更新内存中的流配置 stream := CameraToStream(updatedCamera) err = Storage.StreamEdit(cameraID, stream) if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameraUpdate", "call": "StreamEdit", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "message": "Camera updated successfully", }) } // HTTPAPIServerCameraDelete 删除摄像头 func HTTPAPIServerCameraDelete(c *gin.Context) { if !Storage.Server.DatabaseEnabled { c.JSON(http.StatusServiceUnavailable, gin.H{ "error": "Database is not enabled", }) return } cameraID := c.Param("uuid") if cameraID == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "Camera ID is required", }) return } // 检查摄像头是否存在 existingCamera, err := Storage.dbManager.GetCameraByID(cameraID) if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameraDelete", "call": "GetCameraByID", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } if existingCamera == nil { c.JSON(http.StatusNotFound, gin.H{ "error": "Camera not found", }) return } // 从内存中删除流 err = Storage.StreamDelete(cameraID) if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameraDelete", "call": "StreamDelete", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "message": "Camera deleted successfully", }) } // HTTPAPIServerCameraGet 获取单个摄像头信息 func HTTPAPIServerCameraGet(c *gin.Context) { if !Storage.Server.DatabaseEnabled { c.JSON(http.StatusServiceUnavailable, gin.H{ "error": "Database is not enabled", }) return } cameraID := c.Param("uuid") if cameraID == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "Camera ID is required", }) return } camera, err := Storage.dbManager.GetCameraByID(cameraID) if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameraGet", "call": "GetCameraByID", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } if camera == nil { c.JSON(http.StatusNotFound, gin.H{ "error": "Camera not found", }) return } // 检查流状态 status := "offline" streamID := fmt.Sprintf("%d", camera.CameraID) if stream, exists := Storage.Streams[streamID]; exists { if len(stream.Channels) > 0 { for _, channel := range stream.Channels { if channel.runLock { status = "online" break } } } } response := CameraResponse{ CameraID: camera.CameraID, CameraName: getStringValue(camera.CameraName), IP: camera.IP, Port: camera.Port, Username: getStringValue(camera.Username), // Password: camera.Password, // 不返回密码 URL: camera.URL, CameraProduce: getStringValue(camera.CameraProduce), DeviceType: getStringValue(camera.DeviceType), UnitCode: getStringValue(camera.UnitCode), NvrProduce: getStringValue(camera.NvrProduce), StreamStatus: status, CreateTime: getTimeValue(camera.CreateTime), UpdateTime: getTimeValue(camera.UpdateTime), } c.JSON(http.StatusOK, response) } // HTTPAPIServerCameraRefresh 刷新摄像头列表(从数据库重新加载) func HTTPAPIServerCameraRefresh(c *gin.Context) { if !Storage.Server.DatabaseEnabled { c.JSON(http.StatusServiceUnavailable, gin.H{ "error": "Database is not enabled", }) return } err := Storage.RefreshStreamsFromDatabase() if err != nil { log.WithFields(logrus.Fields{ "module": "api", "func": "HTTPAPIServerCameraRefresh", "call": "RefreshStreamsFromDatabase", }).Errorln(err.Error()) c.JSON(http.StatusInternalServerError, gin.H{ "error": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "message": "Cameras refreshed successfully", }) } // HTTPAPIServerDatabaseStatus 获取数据库状态 func HTTPAPIServerDatabaseStatus(c *gin.Context) { status := Storage.GetDatabaseStatus() c.JSON(http.StatusOK, status) }