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.
343 lines
8.1 KiB
Go
343 lines
8.1 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// JavaAPIResponse 标准化的Java API响应格式
|
|
type JavaAPIResponse struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
Data interface{} `json:"data"`
|
|
Success bool `json:"success"`
|
|
}
|
|
|
|
// CameraListResponse 摄像头列表响应
|
|
type CameraListResponse struct {
|
|
Total int `json:"total"`
|
|
Cameras []Camera `json:"cameras"`
|
|
}
|
|
|
|
// StreamListResponse 流列表响应
|
|
type StreamListResponse struct {
|
|
Total int `json:"total"`
|
|
Streams []Stream `json:"streams"`
|
|
}
|
|
|
|
// Camera 摄像头信息结构
|
|
type Camera struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
IP string `json:"ip"`
|
|
Port int `json:"port"`
|
|
Username string `json:"username"`
|
|
Password string `json:"password,omitempty"` // 敏感信息可选返回
|
|
RTSPURL string `json:"rtsp_url"`
|
|
Status string `json:"status"`
|
|
Enabled bool `json:"enabled"`
|
|
DeviceType string `json:"device_type"`
|
|
UnitCode string `json:"unit_code"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
PlayURLs PlayURLs `json:"play_urls"`
|
|
}
|
|
|
|
// Stream 流信息结构
|
|
type Stream struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Channels map[string]string `json:"channels"`
|
|
PlayURLs PlayURLs `json:"play_urls"`
|
|
}
|
|
|
|
// PlayURLs 播放地址结构
|
|
type PlayURLs struct {
|
|
HLS string `json:"hls"`
|
|
WebRTC string `json:"webrtc"`
|
|
MSE string `json:"mse"`
|
|
All string `json:"all"`
|
|
}
|
|
|
|
// HTTPJavaAPICameras Java项目专用的摄像头列表API
|
|
func HTTPJavaAPICameras(c *gin.Context) {
|
|
if !Storage.ServerHTTPDemo() {
|
|
c.JSON(http.StatusForbidden, JavaAPIResponse{
|
|
Code: 403,
|
|
Message: "Demo mode is disabled",
|
|
Success: false,
|
|
})
|
|
return
|
|
}
|
|
|
|
// 获取查询参数
|
|
unitCode := c.Query("unit_code")
|
|
status := c.Query("status")
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
|
|
|
var cameras []Camera
|
|
var total int
|
|
|
|
// 如果数据库启用,从数据库获取
|
|
if Storage.ServerDatabaseEnabled() {
|
|
dbCameras, err := Storage.DatabaseGetCameras()
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, JavaAPIResponse{
|
|
Code: 500,
|
|
Message: fmt.Sprintf("Database error: %v", err),
|
|
Success: false,
|
|
})
|
|
return
|
|
}
|
|
|
|
// 转换数据库摄像头为API格式
|
|
for _, dbCamera := range dbCameras {
|
|
camera := Camera{
|
|
ID: dbCamera.ID,
|
|
Name: dbCamera.Name,
|
|
IP: dbCamera.IP,
|
|
Port: dbCamera.Port,
|
|
Username: dbCamera.Username,
|
|
RTSPURL: dbCamera.RTSPURL,
|
|
Status: dbCamera.Status,
|
|
Enabled: dbCamera.Enabled,
|
|
DeviceType: dbCamera.DeviceType,
|
|
UnitCode: dbCamera.UnitCode,
|
|
CreatedAt: dbCamera.CreatedAt,
|
|
UpdatedAt: dbCamera.UpdatedAt,
|
|
PlayURLs: generatePlayURLs(dbCamera.ID),
|
|
}
|
|
|
|
// 过滤条件
|
|
if unitCode != "" && camera.UnitCode != unitCode {
|
|
continue
|
|
}
|
|
if status != "" && camera.Status != status {
|
|
continue
|
|
}
|
|
|
|
cameras = append(cameras, camera)
|
|
}
|
|
} else {
|
|
// 从流配置获取
|
|
streamsList := Storage.StreamsList()
|
|
for streamID := range streamsList {
|
|
camera := Camera{
|
|
ID: streamID,
|
|
Name: fmt.Sprintf("Stream %s", streamID),
|
|
Status: "online",
|
|
Enabled: true,
|
|
PlayURLs: generatePlayURLs(streamID),
|
|
}
|
|
cameras = append(cameras, camera)
|
|
}
|
|
}
|
|
|
|
total = len(cameras)
|
|
|
|
// 分页处理
|
|
start := (page - 1) * size
|
|
end := start + size
|
|
if start > total {
|
|
cameras = []Camera{}
|
|
} else if end > total {
|
|
cameras = cameras[start:]
|
|
} else {
|
|
cameras = cameras[start:end]
|
|
}
|
|
|
|
response := JavaAPIResponse{
|
|
Code: 200,
|
|
Message: "Success",
|
|
Success: true,
|
|
Data: CameraListResponse{
|
|
Total: total,
|
|
Cameras: cameras,
|
|
},
|
|
}
|
|
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// HTTPJavaAPIStreams Java项目专用的流列表API
|
|
func HTTPJavaAPIStreams(c *gin.Context) {
|
|
if !Storage.ServerHTTPDemo() {
|
|
c.JSON(http.StatusForbidden, JavaAPIResponse{
|
|
Code: 403,
|
|
Message: "Demo mode is disabled",
|
|
Success: false,
|
|
})
|
|
return
|
|
}
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
|
|
|
streamsList := Storage.StreamsList()
|
|
var streams []Stream
|
|
|
|
for streamID, streamData := range streamsList {
|
|
stream := Stream{
|
|
ID: streamID,
|
|
Name: fmt.Sprintf("Stream %s", streamID),
|
|
Channels: make(map[string]string),
|
|
PlayURLs: generatePlayURLs(streamID),
|
|
}
|
|
|
|
// 获取通道信息
|
|
if streamData != nil {
|
|
for channelID := range streamData.Channels {
|
|
stream.Channels[channelID] = fmt.Sprintf("Channel %s", channelID)
|
|
}
|
|
}
|
|
|
|
streams = append(streams, stream)
|
|
}
|
|
|
|
total := len(streams)
|
|
|
|
// 分页处理
|
|
start := (page - 1) * size
|
|
end := start + size
|
|
if start > total {
|
|
streams = []Stream{}
|
|
} else if end > total {
|
|
streams = streams[start:]
|
|
} else {
|
|
streams = streams[start:end]
|
|
}
|
|
|
|
response := JavaAPIResponse{
|
|
Code: 200,
|
|
Message: "Success",
|
|
Success: true,
|
|
Data: StreamListResponse{
|
|
Total: total,
|
|
Streams: streams,
|
|
},
|
|
}
|
|
|
|
c.JSON(http.StatusOK, response)
|
|
}
|
|
|
|
// HTTPJavaAPICameraDetail 获取摄像头详情
|
|
func HTTPJavaAPICameraDetail(c *gin.Context) {
|
|
cameraID := c.Param("id")
|
|
if cameraID == "" {
|
|
c.JSON(http.StatusBadRequest, JavaAPIResponse{
|
|
Code: 400,
|
|
Message: "Camera ID is required",
|
|
Success: false,
|
|
})
|
|
return
|
|
}
|
|
|
|
if Storage.ServerDatabaseEnabled() {
|
|
camera, err := Storage.DatabaseGetCamera(cameraID)
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, JavaAPIResponse{
|
|
Code: 404,
|
|
Message: "Camera not found",
|
|
Success: false,
|
|
})
|
|
return
|
|
}
|
|
|
|
apiCamera := Camera{
|
|
ID: camera.ID,
|
|
Name: camera.Name,
|
|
IP: camera.IP,
|
|
Port: camera.Port,
|
|
Username: camera.Username,
|
|
RTSPURL: camera.RTSPURL,
|
|
Status: camera.Status,
|
|
Enabled: camera.Enabled,
|
|
DeviceType: camera.DeviceType,
|
|
UnitCode: camera.UnitCode,
|
|
CreatedAt: camera.CreatedAt,
|
|
UpdatedAt: camera.UpdatedAt,
|
|
PlayURLs: generatePlayURLs(camera.ID),
|
|
}
|
|
|
|
c.JSON(http.StatusOK, JavaAPIResponse{
|
|
Code: 200,
|
|
Message: "Success",
|
|
Success: true,
|
|
Data: apiCamera,
|
|
})
|
|
} else {
|
|
// 从流配置获取
|
|
if !Storage.StreamExist(cameraID) {
|
|
c.JSON(http.StatusNotFound, JavaAPIResponse{
|
|
Code: 404,
|
|
Message: "Stream not found",
|
|
Success: false,
|
|
})
|
|
return
|
|
}
|
|
|
|
camera := Camera{
|
|
ID: cameraID,
|
|
Name: fmt.Sprintf("Stream %s", cameraID),
|
|
Status: "online",
|
|
Enabled: true,
|
|
PlayURLs: generatePlayURLs(cameraID),
|
|
}
|
|
|
|
c.JSON(http.StatusOK, JavaAPIResponse{
|
|
Code: 200,
|
|
Message: "Success",
|
|
Success: true,
|
|
Data: camera,
|
|
})
|
|
}
|
|
}
|
|
|
|
// HTTPJavaAPISystemInfo 获取系统信息
|
|
func HTTPJavaAPISystemInfo(c *gin.Context) {
|
|
systemInfo := map[string]interface{}{
|
|
"version": "1.0.0",
|
|
"database_enabled": Storage.ServerDatabaseEnabled(),
|
|
"demo_enabled": Storage.ServerHTTPDemo(),
|
|
"total_streams": len(Storage.StreamsList()),
|
|
"server_time": time.Now().Format(time.RFC3339),
|
|
}
|
|
|
|
if Storage.ServerDatabaseEnabled() {
|
|
cameras, err := Storage.DatabaseGetCameras()
|
|
if err == nil {
|
|
systemInfo["total_cameras"] = len(cameras)
|
|
onlineCount := 0
|
|
for _, camera := range cameras {
|
|
if camera.Status == "online" {
|
|
onlineCount++
|
|
}
|
|
}
|
|
systemInfo["online_cameras"] = onlineCount
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, JavaAPIResponse{
|
|
Code: 200,
|
|
Message: "Success",
|
|
Success: true,
|
|
Data: systemInfo,
|
|
})
|
|
}
|
|
|
|
// generatePlayURLs 生成播放地址
|
|
func generatePlayURLs(streamID string) PlayURLs {
|
|
baseURL := "http://localhost:8083" // 可以从配置获取
|
|
return PlayURLs{
|
|
HLS: fmt.Sprintf("%s/stream/%s/channel/0/hls/live/index.m3u8", baseURL, streamID),
|
|
WebRTC: fmt.Sprintf("%s/pages/player/webrtc/%s/0", baseURL, streamID),
|
|
MSE: fmt.Sprintf("%s/pages/player/mse/%s/0", baseURL, streamID),
|
|
All: fmt.Sprintf("%s/pages/player/all/%s/0", baseURL, streamID),
|
|
}
|
|
} |