84 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			84 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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 int32, 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, uint32(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)
 | |
| 	}
 | |
| }
 | 
