package main import ( "net/http" "time" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/sirupsen/logrus" ) // 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 摄像头响应结构 type CameraResponse struct { ID string `json:"id"` Name string `json:"name"` IP string `json:"ip"` Username string `json:"username"` Password string `json:"password,omitempty"` // 密码在响应中可选 RTSPURL string `json:"rtsp_url"` Enabled bool `json:"enabled"` Status string `json:"status"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // HTTPAPIServerCameras 获取所有摄像头列表 func HTTPAPIServerCameras(c *gin.Context) { if !Storage.Server.DatabaseEnabled { c.JSON(http.StatusServiceUnavailable, gin.H{ "error": "Database is not enabled", }) return } if Storage.dbManager == nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": "Database manager not initialized", }) 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 response []CameraResponse for _, camera := range cameras { status := "offline" if stream, exists := Storage.Streams[camera.ID]; exists { if len(stream.Channels) > 0 { for _, channel := range stream.Channels { if channel.runLock { status = "online" break } } } } response = append(response, CameraResponse{ ID: camera.ID, Name: camera.Name, IP: camera.IP, Username: camera.Username, // Password: camera.Password, // 不返回密码 RTSPURL: camera.RTSPURL, Enabled: camera.Enabled, Status: status, CreatedAt: camera.CreatedAt, UpdatedAt: camera.UpdatedAt, }) } c.JSON(http.StatusOK, gin.H{ "cameras": response, "count": len(response), }) } // 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 } // 生成新的UUID cameraID := uuid.New().String() // 创建摄像头记录 camera := Camera{ ID: cameraID, Name: req.Name, IP: req.IP, Username: req.Username, Password: req.Password, RTSPURL: req.RTSPURL, Enabled: req.Enabled, CreatedAt: time.Now(), UpdatedAt: time.Now(), } // 保存到数据库 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 } // 转换为流配置并添加到内存 stream := CameraToStream(camera) err = Storage.StreamAdd(cameraID, 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": 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 } // 更新摄像头信息 updatedCamera := Camera{ ID: cameraID, Name: req.Name, IP: req.IP, Username: req.Username, Password: req.Password, RTSPURL: req.RTSPURL, Enabled: req.Enabled, CreatedAt: existingCamera.CreatedAt, UpdatedAt: time.Now(), } // 更新数据库 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" if stream, exists := Storage.Streams[camera.ID]; exists { if len(stream.Channels) > 0 { for _, channel := range stream.Channels { if channel.runLock { status = "online" break } } } } response := CameraResponse{ ID: camera.ID, Name: camera.Name, IP: camera.IP, Username: camera.Username, // Password: camera.Password, // 不返回密码 RTSPURL: camera.RTSPURL, Enabled: camera.Enabled, Status: status, CreatedAt: camera.CreatedAt, UpdatedAt: camera.UpdatedAt, } 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) }