first commit
This commit is contained in:
@@ -9,13 +9,11 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Modified device data storage path
|
||||
var (
|
||||
devicesBaseDir = "/data/devices"
|
||||
deviceDataList []DeviceData
|
||||
)
|
||||
|
||||
// InitializeDevicesFromServiceConfig Initialize device data from service configuration
|
||||
func InitializeDevicesFromServiceConfig() ([]DeviceData, error) {
|
||||
deviceDataMutex.Lock()
|
||||
defer deviceDataMutex.Unlock()
|
||||
@@ -38,15 +36,12 @@ func InitializeDevicesFromServiceConfig() ([]DeviceData, error) {
|
||||
|
||||
logger.Logger.Printf("Loaded %d devices from service configuration", len(configs))
|
||||
|
||||
// Clear existing device data
|
||||
deviceDataList = []DeviceData{}
|
||||
|
||||
// Process each device and save to individual files
|
||||
for i, config := range configs {
|
||||
processedData := ProcessDeviceDataForInference(config)
|
||||
deviceDataList = append(deviceDataList, processedData)
|
||||
|
||||
// Save to individual device file
|
||||
if err := saveDeviceToFile(processedData); err != nil {
|
||||
logger.Logger.Printf("Failed to save the device file [%s]: %v", processedData.DeviceUUID, err)
|
||||
continue
|
||||
@@ -58,11 +53,9 @@ func InitializeDevicesFromServiceConfig() ([]DeviceData, error) {
|
||||
return deviceDataList, nil
|
||||
}
|
||||
|
||||
// saveDeviceToFile Save individual device data to separate file
|
||||
func saveDeviceToFile(deviceData DeviceData) error {
|
||||
filePath := filepath.Join(devicesBaseDir, fmt.Sprintf("device_%s.json", deviceData.DeviceUUID))
|
||||
|
||||
// Clean device data to ensure no invalid characters
|
||||
cleanedData := cleanDeviceData(deviceData)
|
||||
|
||||
data, err := json.MarshalIndent(cleanedData, "", " ")
|
||||
@@ -71,7 +64,6 @@ func saveDeviceToFile(deviceData DeviceData) error {
|
||||
return fmt.Errorf("Device data serialization failed: %v", err)
|
||||
}
|
||||
|
||||
// Write directly to file
|
||||
if err := os.WriteFile(filePath, data, 0644); err != nil {
|
||||
return fmt.Errorf("Failed to write device file: %v", err)
|
||||
}
|
||||
@@ -80,11 +72,9 @@ func saveDeviceToFile(deviceData DeviceData) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// cleanDeviceData Clean device data, remove possible invalid characters
|
||||
func cleanDeviceData(data DeviceData) DeviceData {
|
||||
cleaned := data
|
||||
|
||||
// Clean string fields
|
||||
cleaned.DeviceUUID = cleanString(data.DeviceUUID)
|
||||
cleaned.TaskID = cleanString(data.TaskID)
|
||||
cleaned.CameraRTSP = cleanString(data.CameraRTSP)
|
||||
@@ -92,9 +82,8 @@ func cleanDeviceData(data DeviceData) DeviceData {
|
||||
cleaned.UploadURL = cleanString(data.UploadURL)
|
||||
cleaned.DetectAreaStr = cleanString(data.DetectAreaStr)
|
||||
|
||||
// Ensure numeric fields are valid
|
||||
if cleaned.Confidence < 0 || cleaned.Confidence > 100 {
|
||||
cleaned.Confidence = 70 // Default value
|
||||
cleaned.Confidence = 70
|
||||
}
|
||||
if cleaned.CameraChannel < 0 {
|
||||
cleaned.CameraChannel = 0
|
||||
@@ -106,14 +95,14 @@ func cleanDeviceData(data DeviceData) DeviceData {
|
||||
cleaned.Temperature = 0
|
||||
}
|
||||
if cleaned.TemperatureThreshold <= 0 {
|
||||
cleaned.TemperatureThreshold = 45.0 // Default value
|
||||
cleaned.TemperatureThreshold = 45.0
|
||||
}
|
||||
|
||||
return cleaned
|
||||
}
|
||||
|
||||
func cleanString(s string) string {
|
||||
// Remove control characters and invalid Unicode characters
|
||||
|
||||
return strings.Map(func(r rune) rune {
|
||||
if r == 0xFFFD { // Unicode replacement character
|
||||
return -1
|
||||
@@ -125,12 +114,10 @@ func cleanString(s string) string {
|
||||
}, s)
|
||||
}
|
||||
|
||||
// GetDeviceDataList Get device data list
|
||||
func GetDeviceDataList() []DeviceData {
|
||||
deviceDataMutex.Lock()
|
||||
defer deviceDataMutex.Unlock()
|
||||
|
||||
// If no data in memory, try to load from device files
|
||||
if len(deviceDataList) == 0 {
|
||||
logger.Logger.Printf("No device data in memory, loading from device files...")
|
||||
if err := loadDevicesFromFiles(); err != nil {
|
||||
@@ -139,18 +126,15 @@ func GetDeviceDataList() []DeviceData {
|
||||
}
|
||||
}
|
||||
|
||||
// Return copy
|
||||
result := make([]DeviceData, len(deviceDataList))
|
||||
copy(result, deviceDataList)
|
||||
return result
|
||||
}
|
||||
|
||||
// loadDevicesFromFiles Load data from device files
|
||||
func loadDevicesFromFiles() error {
|
||||
// Clear existing data
|
||||
deviceDataList = []DeviceData{}
|
||||
|
||||
// Read all files in device directory
|
||||
files, err := filepath.Glob(filepath.Join(devicesBaseDir, "device_*.json"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to find device files: %v", err)
|
||||
@@ -179,7 +163,6 @@ func loadDevicesFromFiles() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateDeviceData Update device data
|
||||
func UpdateDeviceData(data DeviceData) error {
|
||||
deviceDataMutex.Lock()
|
||||
defer deviceDataMutex.Unlock()
|
||||
@@ -189,7 +172,6 @@ func UpdateDeviceData(data DeviceData) error {
|
||||
// Clean input data
|
||||
cleanedData := cleanDeviceData(data)
|
||||
|
||||
// Find if device with same DeviceUUID already exists
|
||||
found := false
|
||||
for i, existing := range deviceDataList {
|
||||
if existing.DeviceUUID == cleanedData.DeviceUUID {
|
||||
@@ -200,13 +182,11 @@ func UpdateDeviceData(data DeviceData) error {
|
||||
}
|
||||
}
|
||||
|
||||
// If not exists, add to list
|
||||
if !found {
|
||||
logger.Logger.Printf("Adding new device to list: DeviceUUID=%s", cleanedData.DeviceUUID)
|
||||
deviceDataList = append(deviceDataList, cleanedData)
|
||||
}
|
||||
|
||||
// Save to individual file
|
||||
if err := saveDeviceToFile(cleanedData); err != nil {
|
||||
logger.Logger.Printf("Failed to save device file: %v", err)
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package connect
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"FireLeave_tool/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
InferenceProcesses sync.Map // key: deviceUUID string, value: *exec.Cmd
|
||||
|
||||
// 记录最后一次收到心跳的时间
|
||||
inferenceLastHeartbeat sync.Map // key: deviceUUID string, value: time.Time
|
||||
)
|
||||
|
||||
// UpdateInferenceHeartbeat 每收到一帧 /video/post 就调用这个
|
||||
func UpdateInferenceHeartbeat(deviceUUID string) {
|
||||
inferenceLastHeartbeat.Store(deviceUUID, time.Now())
|
||||
|
||||
}
|
||||
|
||||
// ShouldRestartInference 判断是否需要重启推理程序
|
||||
func ShouldRestartInference(deviceUUID string) bool {
|
||||
val, ok := inferenceLastHeartbeat.Load(deviceUUID)
|
||||
if !ok {
|
||||
return true // 从未收到过心跳,肯定要启动
|
||||
}
|
||||
last := val.(time.Time)
|
||||
return time.Since(last) > 85*time.Second
|
||||
}
|
||||
|
||||
// StopInferenceProcess 停止推理进程(供 main 和 DeviceManager 调用)
|
||||
func StopInferenceProcess(deviceUUID string) {
|
||||
if raw, ok := InferenceProcesses.Load(deviceUUID); ok {
|
||||
if cmd, ok := raw.(*exec.Cmd); ok && cmd.Process != nil {
|
||||
logger.Logger.Printf("正在停止推理进程 (DeviceUUID=%s, PID=%d)", deviceUUID, cmd.Process.Pid)
|
||||
cmd.Process.Kill()
|
||||
cmd.Wait()
|
||||
}
|
||||
InferenceProcesses.Delete(deviceUUID)
|
||||
}
|
||||
}
|
||||
|
||||
// StartInferenceProcess 重启推理程序(保持原端口!)
|
||||
func StartInferenceProcess(deviceData *DeviceData) {
|
||||
|
||||
StopInferenceProcess(deviceData.DeviceUUID)
|
||||
|
||||
port, err := GlobalPortManager.GetPort(deviceData.DeviceUUID)
|
||||
if err != nil {
|
||||
logger.Logger.Printf("获取端口失败,无法重启推理程序 (DeviceUUID=%s): %v", deviceData.DeviceUUID, err)
|
||||
return
|
||||
}
|
||||
|
||||
detectAreaStr := ProcessDetectAreaForInference(deviceData.DetectArea)
|
||||
|
||||
inferenceCmd := exec.Command(
|
||||
"./yolov5",
|
||||
"-s", deviceData.CameraRTSP,
|
||||
"-m", "model",
|
||||
"-c", deviceData.DeviceUUID,
|
||||
"-p", fmt.Sprintf("%d", port),
|
||||
"-w", detectAreaStr,
|
||||
"-r", fmt.Sprintf("%d", deviceData.Confidence),
|
||||
)
|
||||
|
||||
inferenceCmd.Stdout = os.Stdout
|
||||
inferenceCmd.Stderr = os.Stderr
|
||||
|
||||
logger.Logger.Printf("正在重启推理程序 (使用原端口 %d): %v", port, inferenceCmd.Args)
|
||||
|
||||
if err := inferenceCmd.Start(); err != nil {
|
||||
logger.Logger.Printf("推理程序重启失败 (DeviceUUID=%s): %v", deviceData.DeviceUUID, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 保存进程对象
|
||||
InferenceProcesses.Store(deviceData.DeviceUUID, inferenceCmd)
|
||||
logger.Logger.Printf("推理程序已成功重启,PID=%d (DeviceUUID=%s, Port=%d)",
|
||||
inferenceCmd.Process.Pid, deviceData.DeviceUUID, port)
|
||||
|
||||
// 重启后立即刷新一次心跳,防止 30s 检测又触发
|
||||
UpdateInferenceHeartbeat(deviceData.DeviceUUID)
|
||||
}
|
||||
@@ -20,7 +20,7 @@ type PortManager struct {
|
||||
}
|
||||
|
||||
func NewPortManager() *PortManager {
|
||||
// 推理端口范围:58881-58890(HTTP),支持最多10个设备
|
||||
|
||||
ports := []int{58881, 58882, 58883, 58884, 58885, 58886, 58887, 58888, 58889, 58890}
|
||||
|
||||
// 初始化可用端口映射
|
||||
|
||||
@@ -511,6 +511,7 @@ func (c *WSClient) heartbeatLoop() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *WSClient) reRegisterAndResubscribe() {
|
||||
// 1. 等待连接稳定
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
Reference in New Issue
Block a user