You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
543 lines
14 KiB
Go
543 lines
14 KiB
Go
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)
|
|
}
|