package timer import ( "context" "log/slog" "sync" "time" ) // TurnEndCallback defines the function signature for actions to be performed when a turn ends. type TurnEndCallback func(ctx context.Context, roomID string) // TickCallback defines the function signature for actions to be performed on each timer tick. type TickCallback func(ctx context.Context, roomID string, timeLeft uint32) type RoomTimer struct { ticker *time.Ticker done chan bool roomID string onTurnEnd TurnEndCallback onTick TickCallback log *slog.Logger } var ( timers = make(map[string]*RoomTimer) mu sync.Mutex ) // StartTurnTimer initializes and starts a new turn timer for a given room. func StartTurnTimer(ctx context.Context, roomID string, timeLeft uint32, onTurnEnd TurnEndCallback, onTick TickCallback, logger *slog.Logger) { mu.Lock() defer mu.Unlock() if _, exists := timers[roomID]; exists { logger.Debug("trying to launch already running timer", "room_id", roomID) return // Timer already running } ticker := time.NewTicker(1 * time.Second) done := make(chan bool) rt := &RoomTimer{ ticker: ticker, done: done, roomID: roomID, onTurnEnd: onTurnEnd, onTick: onTick, log: logger, } timers[roomID] = rt go func() { currentLeft := timeLeft for { select { case <-done: return case <-ticker.C: if currentLeft <= 0 { rt.onTurnEnd(ctx, roomID) StopTurnTimer(roomID) return } rt.onTick(ctx, roomID, currentLeft) currentLeft-- } } }() } // StopTurnTimer stops the timer for a given room. func StopTurnTimer(roomID string) { mu.Lock() defer mu.Unlock() if rt, exists := timers[roomID]; exists { rt.ticker.Stop() close(rt.done) delete(timers, roomID) rt.log.Info("timer stopped", "room_id", roomID) } }