package connect import ( "fmt" "os" "os/exec" "strings" "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()) // 输出心跳日志 if strings.Contains(deviceUUID, "_fire_check") { logger.Logger.Printf("推理心跳收到 | 时间: %s | UUID: %s | 类型: fire_check", time.Now().Format("2006/01/02 15:04:05.000"), deviceUUID) } else { logger.Logger.Printf("推理心跳收到 | 时间: %s | UUID: %s | 类型: fire_leave", time.Now().Format("2006/01/02 15:04:05.000"), deviceUUID) } } // 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) { // 重启fire_leave推理程序 StopInferenceProcess(deviceData.DeviceUUID) portFireLeave, err := GlobalPortManager.GetPort(deviceData.DeviceUUID) if err != nil { logger.Logger.Printf("获取fire_leave端口失败,无法重启推理程序 (DeviceUUID=%s): %v", deviceData.DeviceUUID, err) return } // 重启fire_check推理程序 StopInferenceProcess(fmt.Sprintf("%s_fire_check", deviceData.DeviceUUID)) portFireCheck, err := GlobalPortManager.GetPort(fmt.Sprintf("%s_fire_check", deviceData.DeviceUUID)) if err != nil { logger.Logger.Printf("获取fire_check端口失败,无法重启推理程序 (DeviceUUID=%s): %v", deviceData.DeviceUUID, err) return } // 为fire_leave推理程序获取检测区域 fireLeaveDetectAreaStr := ProcessDetectAreaForInference(deviceData.FireLeaveDetectArea) // 启动fire_leave推理程序 inferenceCmdFireLeave := exec.Command( "./yolov5", "-s", deviceData.CameraRTSP, "-m", "model", "-c", deviceData.DeviceUUID, "-p", fmt.Sprintf("%d", portFireLeave), "-w", fireLeaveDetectAreaStr, "-r", fmt.Sprintf("%d", deviceData.Confidence), ) inferenceCmdFireLeave.Stdout = os.Stdout inferenceCmdFireLeave.Stderr = os.Stderr logger.Logger.Printf("正在重启fire_leave推理程序 (使用原端口 %d): %v", portFireLeave, inferenceCmdFireLeave.Args) if err := inferenceCmdFireLeave.Start(); err != nil { logger.Logger.Printf("fire_leave推理程序重启失败 (DeviceUUID=%s): %v", deviceData.DeviceUUID, err) return } // 保存fire_leave进程对象 InferenceProcesses.Store(deviceData.DeviceUUID, inferenceCmdFireLeave) logger.Logger.Printf("fire_leave推理程序已成功重启,PID=%d (DeviceUUID=%s, Port=%d)", inferenceCmdFireLeave.Process.Pid, deviceData.DeviceUUID, portFireLeave) // 为fire_check推理程序获取检测区域 fireCheckDetectAreaStr := ProcessDetectAreaForInference(deviceData.FireCheckDetectArea) // 启动fire_check推理程序 inferenceCmdFireCheck := exec.Command( "./yolov5", "-s", deviceData.CameraRTSP, "-m", "fire_check", "-c", fmt.Sprintf("%s_fire_check", deviceData.DeviceUUID), "-p", fmt.Sprintf("%d", portFireCheck), "-w", fireCheckDetectAreaStr, "-r", fmt.Sprintf("%d", deviceData.Confidence), "-R", ) inferenceCmdFireCheck.Stdout = os.Stdout inferenceCmdFireCheck.Stderr = os.Stderr logger.Logger.Printf("正在重启fire_check推理程序 (使用原端口 %d): %v", portFireCheck, inferenceCmdFireCheck.Args) if err := inferenceCmdFireCheck.Start(); err != nil { logger.Logger.Printf("fire_check推理程序重启失败 (DeviceUUID=%s): %v", deviceData.DeviceUUID, err) return } // 保存fire_check进程对象 InferenceProcesses.Store(fmt.Sprintf("%s_fire_check", deviceData.DeviceUUID), inferenceCmdFireCheck) logger.Logger.Printf("fire_check推理程序已成功重启,PID=%d (DeviceUUID=%s, Port=%d)", inferenceCmdFireCheck.Process.Pid, deviceData.DeviceUUID, portFireCheck) // 重启后立即刷新一次心跳,防止 30s 检测又触发 UpdateInferenceHeartbeat(deviceData.DeviceUUID) UpdateInferenceHeartbeat(fmt.Sprintf("%s_fire_check", deviceData.DeviceUUID)) }