v0.13.0 web and terminal client enhance, replay api, linux server deploy, doc and dependency update
test / test (push) Canceled after 0s

This commit is contained in:
lixen committed 2026-09-28 22:35:52 -04:00
1 parent 52ac0fe31a
commit f1ac4cbbe7
71 files changed
+7677 -537

No files matched your search

+40 -20
View File
@@ -29,16 +29,18 @@ const (
// Service coordinates game state, user management, and storage
type Service struct {
games map[string]*game.Game
mu sync.RWMutex
store *storage.Store
jwt *auth.JWT
kdf chan struct{} // Argon2id concurrency slots
waiter *WaitRegistry
computerGames atomic.Int32 // Active games with computer players
finishedTTL time.Duration
anonymousTTL time.Duration
maxUsers atomic.Int64
games map[string]*game.Game
mu sync.RWMutex
store *storage.Store
jwt *auth.JWT
kdf chan struct{} // Argon2id concurrency slots
waiter *WaitRegistry
finishedTTL time.Duration
anonymousTTL time.Duration
maxUsers atomic.Int64
integrityMode IntegrityMode
integrityCursor string // last game ID the integrity sweep verified; cleanup goroutine only
}
// New creates a service with optional storage. jwtSecret signs session tokens
@@ -64,6 +66,9 @@ func New(store *storage.Store, jwtSecret []byte) (*Service, error) {
anonymousTTL: AnonymousGameTTL,
}
s.maxUsers.Store(DefaultMaxUsers)
if store != nil {
store.SetGameMissingHandler(s.evictMissingGame)
}
return s, nil
}
@@ -115,14 +120,30 @@ func (s *Service) RegisterWait(gameID string, moveCount int, ctx context.Context
return s.waiter.RegisterWait(gameID, moveCount, ctx)
}
// CanCreateComputerGame checks if a new computer game can be created
// CanCreateComputerGame reports whether the computer game limit leaves room
// for another game; CreateGame re-checks under its lock.
func (s *Service) CanCreateComputerGame() bool {
return s.computerGames.Load() < MaxComputerGames
return s.GetComputerGameCount() < MaxComputerGames
}
// GetComputerGameCount returns current computer game count
func (s *Service) GetComputerGameCount() int32 {
return s.computerGames.Load()
// GetComputerGameCount returns the number of unfinished loaded games with a
// computer player. Finished games stay loaded for a while but need no engine,
// so they do not count against MaxComputerGames.
func (s *Service) GetComputerGameCount() int {
s.mu.RLock()
defer s.mu.RUnlock()
return s.activeComputerGamesLocked()
}
// activeComputerGamesLocked counts as GetComputerGameCount. Caller holds s.mu.
func (s *Service) activeComputerGamesLocked() int {
active := 0
for _, g := range s.games {
if g.HasComputerPlayer() && !g.State().IsTerminal() {
active++
}
}
return active
}
// Shutdown gracefully shuts down the service
@@ -146,8 +167,9 @@ func (s *Service) Shutdown(timeout time.Duration) error {
return errors.Join(errs...)
}
// RunCleanupJob periodically removes expired sessions, unloads idle games, and
// deletes anonymous games past their retention.
// RunCleanupJob periodically removes expired sessions, unloads idle games,
// deletes anonymous games past their retention, and runs the integrity sweep
// when enabled.
func (s *Service) RunCleanupJob(ctx context.Context, interval time.Duration) {
s.cleanupExpired()
ticker := time.NewTicker(interval)
@@ -173,6 +195,7 @@ func (s *Service) cleanupExpired() {
}
}
s.cleanupGames(now)
s.checkIntegrity(now)
}
// cleanupGames unloads terminal games after the finished-game TTL and
@@ -199,9 +222,6 @@ func (s *Service) cleanupGames(now time.Time) {
live = append(live, gameID)
continue
}
if g.HasComputerPlayer() {
s.computerGames.Add(-1)
}
delete(s.games, gameID)
}
s.mu.Unlock()