package routes import ( "context" "fmt" "game-driver/internal/middleware" "game-driver/internal/schema" "game-driver/leaf" "game-driver/pkg/audio" "game-driver/pkg/browser" "game-driver/pkg/relay" "game-driver/pkg/tts" "game-driver/pkg/utils" "game-driver/pkg/video" "github.com/go-pkgz/cronrange" "github.com/gopxl/beep/v2/speaker" "go.uber.org/zap" "sync" "time" ) func runAction(c *leaf.Context, item schema.WaitItemModel, rootRules []cronrange.Rule, play func(c context.Context, item schema.WaitItemModel) error) { // 设定默认时间规则 if item.Cron == "" { item.Cron = "* * * *" } rules, err := cronrange.Parse(item.Cron) if err != nil { zap.S().Errorln("解析时间规则异常: ", err) return } a := make(chan bool) defer close(a) // 等待组 var wait sync.WaitGroup defer wait.Wait() ticker := time.NewTicker(time.Second) defer ticker.Stop() wait.Add(1) go func() { defer wait.Done() for { select { case <-c.Done(): return case <-ticker.C: if cronrange.Match(rules, time.Now()) && cronrange.Match(rootRules, time.Now()) { a <- true } else { a <- false } } } }() var cancel context.CancelFunc var m sync.Mutex for { select { case <-c.Done(): if cancel != nil { cancel() } return case r := <-a: if r { if ok := m.TryLock(); ok { ctx, cc := context.WithCancel(context.TODO()) cancel = cc wait.Add(1) go func() { defer wait.Done() defer m.Unlock() defer func() { cancel = nil }() err := play(ctx, item) if err != nil { zap.S().Errorln("执行动作异常: ", err) select { case <-ctx.Done(): return case <-time.After(time.Minute): } } }() } } else if cancel != nil { cancel() cancel = nil } } } } func WaitAction(c *leaf.Context) { payload := leaf.Value[*schema.WaitModel](c, middleware.PayloadJSONKey) // 设定默认时间规则 if payload.Cron == "" { payload.Cron = "* * * *" } rules, err := cronrange.Parse(payload.Cron) if err != nil { zap.S().Errorln("解析时间规则异常: ", err) return } // 等待组 var wait sync.WaitGroup defer wait.Wait() for _, item := range payload.Items { switch item.Type { case schema.WaitAudio: // 执行音乐播放 wait.Add(1) go func() { defer wait.Done() runAction(c, item, rules, audioAction) }() case schema.WaitTTS: // 执行TTS播放 wait.Add(1) go func() { defer wait.Done() runAction(c, item, rules, ttsAction) }() case schema.WaitRelay: // 执行继电器供电 wait.Add(1) go func() { defer wait.Done() runAction(c, item, rules, relayAction) }() case schema.WaitVideo: // 执行视频播放 wait.Add(1) go func() { defer wait.Done() runAction(c, item, rules, videoAction) }() case schema.WaitWeb: // 执行网页打开 wait.Add(1) go func() { defer wait.Done() runAction(c, item, rules, webAction) }() default: zap.S().Infof("不支持的类型: %d\n", item.Type) } } } func audioAction(c context.Context, item schema.WaitItemModel) error { data, err := utils.LinkAudio(item.Data) if err != nil { return fmt.Errorf("音频数据获取异常: %w", err) } if data == nil { return fmt.Errorf("音频数据获取为空") } zap.S().Infoln("播放待机音乐") defer zap.S().Infoln("结束待机音乐") ctrl, closer, e := audio.PlayBgmMP3(data) defer closer() if e != nil { return fmt.Errorf("播放待机音乐异常: %w", e) } <-c.Done() speaker.Lock() ctrl.Streamer = nil speaker.Unlock() return nil } func ttsAction(c context.Context, item schema.WaitItemModel) error { reader, err := tts.DefaultTTS.Get(item.Data) if err != nil { return fmt.Errorf("语音合成异常: %w", err) } zap.S().Infoln("循环播放待机 TTS 语音") defer zap.S().Infoln("结束待机 TTS 语音") for { audio.PlayWav(c, reader) select { case <-c.Done(): return nil case <-time.After(time.Duration(item.Interval) * time.Second): } } } func relayAction(c context.Context, item schema.WaitItemModel) error { r, err := relay.New(item.Data) if err != nil { return fmt.Errorf("继电器初始化异常: %w", err) } defer r.Close() zap.S().Infoln("待机继电器供电") defer zap.S().Infoln("待机继电器断电") _ = r.On(0) <-c.Done() _ = r.Off(0) return nil } func videoAction(c context.Context, item schema.WaitItemModel) error { local, err := utils.LinkVideo(item.Data) if err != nil { return fmt.Errorf("视频文件获取异常: %w", err) } zap.S().Infoln("循环播放待机视频") defer zap.S().Infoln("结束待机视频") utils.BlankOpen() defer utils.BlankClose() for { err := video.Play(c, local) if err != nil { return fmt.Errorf("视频播放异常: %w", err) } select { case <-c.Done(): return nil case <-time.After(time.Duration(item.Interval) * time.Second): } } } func webAction(c context.Context, item schema.WaitItemModel) error { zap.S().Infoln("打开待机网页") // 控制背光 utils.BlankOpen() defer utils.BlankClose() browser.OpenApp(c, item.Data) return nil }