package interlock import ( "context" "fmt" "log/slog" "runtime/debug" "sync" "time" "joylink.club/bj-rtsts-server/config" "joylink.club/bj-rtsts-server/third_party/message" "joylink.club/bj-rtsts-server/third_party/udp" ) // 联锁代理通信接口 type InterlockMessageManager interface { CollectRelayInfo() []*message.InterlockSendMsgPkg HandleDriverInfo(b []byte) GetInterlockRunConfig() *config.InterlockConfig } // 联锁接口 type InterlockProxy interface { // 启动联锁消息功能 Start(manager InterlockMessageManager) // 停止联锁消息功能 Stop() // 发送联锁采集消息 SendCollectMessage(b []byte) } var _default InterlockProxy var initMutex sync.Mutex func Default() InterlockProxy { initMutex.Lock() defer initMutex.Unlock() if _default == nil { // TODO _default = &interlockProxy{} } return _default } type interlockProxy struct { driveInfoUdpServer udp.UdpServer sendCollectUdpClient udp.UdpClient manager InterlockMessageManager collectInfoTaskCancel context.CancelFunc runConfig *config.InterlockConfig } // 驱动信息进行转发 func (i *interlockProxy) handleDriverInfo(b []byte) { handler := i.manager if handler != nil { handler.HandleDriverInfo(b) } } func (i *interlockProxy) Start(manager InterlockMessageManager) { if manager == nil { panic("启动联锁消息服务错误: InterlockMessageManager不能为nil") } if i.manager != nil { panic("启动联锁消息服务错误: 存在正在运行的任务") } i.runConfig = manager.GetInterlockRunConfig() if i.runConfig == nil || i.runConfig.Ip == "" || !i.runConfig.Open { return } i.manager = manager // 初始化客户端、服务端 i.initInterlockProxy() ctx, cancle := context.WithCancel(context.Background()) go i.collectInfoStateTask(ctx) i.collectInfoTaskCancel = cancle } // 采集电路状态发送间隔,单位ms const InterlockMessageSendInterval = 50 // 序列号 var serialNumber uint8 // 定时发送采集电路状态任务 func (i *interlockProxy) collectInfoStateTask(ctx context.Context) { defer func() { if err := recover(); err != nil { slog.Error("定时发送道岔状态任务异常", "error", err, "stack", string(debug.Stack())) debug.PrintStack() } }() for { select { case <-ctx.Done(): return default: } collectInfoStates := i.manager.CollectRelayInfo() for _, state := range collectInfoStates { serialNumber++ state.Header.SerialNumber = serialNumber i.sendCollectUdpClient.SendMsg(state) } time.Sleep(time.Millisecond * InterlockMessageSendInterval) } } func (i *interlockProxy) Stop() { if i.sendCollectUdpClient != nil { i.sendCollectUdpClient.Close() } if i.driveInfoUdpServer != nil { i.driveInfoUdpServer.Close() } if i.collectInfoTaskCancel != nil { i.collectInfoTaskCancel() i.manager = nil } } func (i *interlockProxy) SendCollectMessage(b []byte) { i.sendCollectUdpClient.Send(b) } func (i *interlockProxy) initInterlockProxy() { i.sendCollectUdpClient = udp.NewClient(fmt.Sprintf("%v:%v", i.runConfig.Ip, i.runConfig.RemotePort)) i.driveInfoUdpServer = udp.NewServer(fmt.Sprintf(":%d", i.runConfig.LocalPort), i.handleDriverInfo) i.driveInfoUdpServer.Listen() }