// Package service 提供各种业务服务功能 package service import ( "context" "fmt" "time" "git.huangwc.com/pig/pig-farm-controller/internal/config" "git.huangwc.com/pig/pig-farm-controller/internal/logs" "git.huangwc.com/pig/pig-farm-controller/internal/storage/repository" ) // HeartbeatService 心跳服务,负责管理设备的心跳检测 type HeartbeatService struct { // websocketService WebSocket服务 websocketService *WebSocketService // deviceStatusPool 设备状态池 deviceStatusPool *DeviceStatusPool // deviceRepo 设备仓库 deviceRepo repository.DeviceRepo // logger 日志记录器 logger *logs.Logger // 心跳间隔 heartbeatInterval time.Duration // 手动心跳触发器 triggerChan chan struct{} // ticker 心跳定时器 ticker *time.Ticker // ctx 上下文 ctx context.Context // cancel 取消函数 cancel context.CancelFunc } // NewHeartbeatService 创建心跳服务实例 func NewHeartbeatService(websocketService *WebSocketService, deviceStatusPool *DeviceStatusPool, deviceRepo repository.DeviceRepo, config *config.Config) *HeartbeatService { return &HeartbeatService{ websocketService: websocketService, deviceStatusPool: deviceStatusPool, deviceRepo: deviceRepo, logger: logs.NewLogger(), heartbeatInterval: time.Duration(config.GetHeartbeatInterval()) * time.Second, triggerChan: make(chan struct{}), } } // Start 启动心跳服务 func (hs *HeartbeatService) Start() { // 创建上下文 ctx, cancel := context.WithCancel(context.Background()) hs.cancel = cancel // 创建定时器 hs.logger.Info(fmt.Sprintf("设置心跳间隔为 %d 秒", int(hs.heartbeatInterval.Seconds()))) hs.ticker = time.NewTicker(hs.heartbeatInterval) // 启动心跳goroutine go func() { for { select { case <-hs.ticker.C: hs.handleHeartbeat() case <-hs.triggerChan: hs.handleHeartbeat() case <-ctx.Done(): hs.logger.Info("心跳服务已停止") return } } }() hs.logger.Info("心跳服务已启动") } // Stop 停止心跳服务 func (hs *HeartbeatService) Stop() { if hs == nil { return } if hs.ticker != nil { hs.ticker.Stop() } if hs.cancel != nil { hs.cancel() } hs.logger.Info("[Heartbeat] 心跳任务停止指令已发送") } // TriggerManualHeartbeat 手动触发心跳检测 func (hs *HeartbeatService) TriggerManualHeartbeat() { hs.logger.Info("收到手动触发心跳检测请求") hs.triggerChan <- struct{}{} hs.logger.Info("手动心跳检测完成") } // TriggerManualHeartbeatAsync 手动触发心跳检测且不等待检测结果 func (hs *HeartbeatService) TriggerManualHeartbeatAsync() { hs.logger.Info("收到手动触发异步心跳检测请求") go func() { hs.triggerChan <- struct{}{} hs.logger.Info("手动心跳检测完成") }() } // sendHeartbeat 发送心跳包到所有中继设备 func (hs *HeartbeatService) handleHeartbeat() { // 记录心跳开始日志 hs.logger.Debug("开始发送心跳包") // 获取所有已连接的设备 connectedDevices := hs.websocketService.GetConnectedDevices() // 遍历所有连接的设备并发送心跳包 for _, deviceID := range connectedDevices { // 发送心跳包到设备 response, err := hs.websocketService.SendCommandAndWait(deviceID, "heartbeat", nil, 0) if err != nil { hs.logger.Error(fmt.Sprintf("向设备 %s 发送心跳包失败: %v", deviceID, err)) // 更新设备状态为离线 hs.deviceStatusPool.SetStatus(deviceID, &DeviceStatus{ Active: false, }) continue } // 记录收到心跳响应 hs.logger.Debug(fmt.Sprintf("收到来自设备 %s 的心跳响应: %+v", deviceID, response)) // 更新设备状态为在线 hs.deviceStatusPool.SetStatus(deviceID, &DeviceStatus{ Active: true, }) } hs.logger.Debug("心跳包发送完成") }