package handlers import ( "context" "fmt" "gralias/models" "log/slog" "strconv" "sync" "time" ) type roomTimer struct { ticker *time.Ticker done chan bool } var ( timers = make(map[string]*roomTimer) mu sync.Mutex ) func StartTurnTimer(roomID string, timeLeft uint32) { mu.Lock() defer mu.Unlock() if _, exists := timers[roomID]; exists { slog.Debug("trying to launch already running timer", "room_id", roomID) return // Timer already running } ticker := time.NewTicker(1 * time.Second) done := make(chan bool) timers[roomID] = &roomTimer{ticker: ticker, done: done} go func() { for { select { case <-done: return case <-ticker.C: if timeLeft <= 0 { room, err := repo.RoomGetByID(context.Background(), roomID) if err != nil { log.Error("failed to get room by id", "error", err) StopTurnTimer(roomID) return } log.Info("turn time is over", "room_id", roomID) room.ChangeTurn() room.MimeDone = false if err := repo.RoomUpdate(context.Background(), room); err != nil { log.Error("failed to save room", "error", err) } notify(models.NotifyTurnTimerPrefix+room.ID, strconv.FormatUint(uint64(room.Settings.RoundTime), 10)) notifyBotIfNeeded(room) StopTurnTimer(roomID) return } timeLeft-- notify(models.NotifyTurnTimerPrefix+roomID, fmt.Sprintf("%d", timeLeft)) } } }() } func StopTurnTimer(roomID string) { mu.Lock() defer mu.Unlock() if timer, exists := timers[roomID]; exists { timer.ticker.Stop() close(timer.done) delete(timers, roomID) } }