package play import ( "context" "encoding/json" "errors" "game-driver/config/game" "game-driver/internal/middleware" "game-driver/internal/routes/play/card_pusher" "game-driver/internal/schema" "game-driver/leaf" "game-driver/pkg/card_reader" "game-driver/pkg/utils" "github.com/eclipse/paho.golang/paho" "go.uber.org/zap" "io/fs" "os" "sync" "time" ) type ResponseBody struct { CardId string `json:"card_id"` Empty int `json:"empty"` Error int `json:"error"` OutOk int `json:"out_ok"` num int } func PushCard(ctx context.Context) leaf.HandlerFunc { g := (game.C).(game.ConfigPush) readers := make([]card_reader.Reader, len(g.PushGroups)) devices := make([]*card_pusher.Device, len(g.PushGroups)) for i, group := range g.PushGroups { // 解析配置 gv, _ := json.Marshal(group) zap.S().Infof("关卡配置[%v]: %s", i, string(gv)) // 开始连接读卡器 if group.Read != "" { reader, err := card_reader.NewReader(group.Read) if err != nil { if errors.Is(err, fs.ErrNotExist) { zap.S().Errorf("读卡器串口文件不存在: %s", group.Read) os.Exit(1) } zap.S().Panicf("读卡器串口 %q 连接失败 [%T]: %q", group.Read, err, err) } // 初始化读卡器 err = reader.Init() if err != nil { reader.Close() zap.S().Panicf("读卡器 %q 初始配置失败: %s", group.Read, err) } // 保存读卡器 readers[i] = reader } // 开始连接发卡器 device, err := card_pusher.New(group) if err != nil { zap.S().Panicln("初始化发卡器失败: ", err) } // 保存发卡器 devices[i] = device } go func() { <-ctx.Done() for _, reader := range readers { if reader != nil { _ = reader.Close() } } for _, device := range devices { if device != nil { _ = device.Close() } } }() return func(c *leaf.Context) { payload := leaf.Value[*schema.PlayModal](c, middleware.PayloadJSONKey) var action time.Duration if a, ok := payload.Game["action"]; ok { if v, ok := a.(float64); ok { action = time.Duration(v) } } // 等待组 var wait sync.WaitGroup defer wait.Wait() // 结束信号通道 a := make(chan struct{}) // 发送结束信号 defer close(a) wait.Add(1) go func() { defer wait.Done() select { case <-a: case <-time.After(action * time.Second): body := &ResponseBody{} for _, device := range devices { body.Empty += device.GetEmpty() body.Error += device.GetError() } for i, device := range devices { if device.GetEmpty() == 0 && device.GetError() == 0 && device.GetOutOk() == 0 { body.num = i + 1 device.PushCard() break } } // 延迟1秒获取结果并发送消息 time.AfterFunc(time.Second, func() { if body.num != 0 { // 若卡片就位,读取卡片信息 if devices[body.num-1].GetOutOk() == 1 && readers[body.num-1] != nil { if info := readers[body.num-1].GetCardInfo(); info != nil { body.CardId = info.ID } } body.OutOk += devices[body.num-1].GetOutOk() } publishBody(ctx, c.Properties.ResponseTopic, body) }) } }() // 执行等待信号 Default(c) } } // 发布消息 func publishBody(ctx context.Context, topic string, body *ResponseBody) { if topic != "" { bytes, _ := json.Marshal(body) utils.GlobalMqttClient.Publish(ctx, &paho.Publish{ Topic: topic, Payload: bytes, QoS: 1, }) } }