Files
scrabble-game/backend/internal/lobby/config.go
T
Ilia Denisov c305363ccd
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 14s
CI / ui (pull_request) Successful in 45s
CI / gate (pull_request) Successful in 1s
CI / deploy (pull_request) Successful in 1m4s
feat(lobby): enter the game immediately and wait for the opponent inside it
Quick auto-match no longer waits on a separate screen: Enqueue opens a real game seating the caller with an empty opponent seat (new game status 'open') and the player enters it at once. A second human searching the same variant+rule joins that open game; otherwise a background reaper seats a robot after a 90s + random 0-90s wait, pushing a new in-app opponent_joined event that fills the opponent card and re-enables resign and chat in place.

Matchmaking state is now the open games in the database (the in-memory pool, lobby.poll and lobby.cancel are gone), serialised by a per-bucket advisory lock. While a game is open the starter may move on their turn, but resign, chat and nudge are refused; the lobby and opponent card show "searching for opponent".

Schema edited in the baseline (no prod data): 'open' status, nullable game_players.account_id for the empty seat, and a games.open_deadline_at stamp; jet code regenerated.
2026-06-12 16:00:22 +02:00

48 lines
1.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package lobby
import (
"fmt"
"time"
)
// Config configures auto-match robot substitution: how long an open game waits for a
// human opponent before a robot is substituted, and how often the reaper scans.
type Config struct {
// RobotWait is the fixed minimum an open auto-match game waits for a human
// opponent before it is eligible for robot substitution. Sourced from
// BACKEND_LOBBY_ROBOT_WAIT.
RobotWait time.Duration
// RobotWaitJitter is a random extra wait in [0, RobotWaitJitter) added on top of
// RobotWait per game, so the substitution time varies. Sourced from
// BACKEND_LOBBY_ROBOT_WAIT_JITTER.
RobotWaitJitter time.Duration
// ReaperInterval is how often the reaper scans for open games due for a robot.
// Sourced from BACKEND_LOBBY_REAPER_INTERVAL.
ReaperInterval time.Duration
}
// DefaultConfig returns the matchmaking defaults: a guaranteed 90-second wait for a
// human plus up to 90 random seconds (90180 s total) before a robot substitutes
// (docs/ARCHITECTURE.md §7), scanned every five seconds.
func DefaultConfig() Config {
return Config{
RobotWait: 90 * time.Second,
RobotWaitJitter: 90 * time.Second,
ReaperInterval: 5 * time.Second,
}
}
// Validate reports whether the configuration is usable.
func (c Config) Validate() error {
if c.RobotWait <= 0 {
return fmt.Errorf("lobby: robot wait must be positive, got %s", c.RobotWait)
}
if c.RobotWaitJitter < 0 {
return fmt.Errorf("lobby: robot wait jitter must not be negative, got %s", c.RobotWaitJitter)
}
if c.ReaperInterval <= 0 {
return fmt.Errorf("lobby: reaper interval must be positive, got %s", c.ReaperInterval)
}
return nil
}