v0.13.0 web and terminal client enhance, replay api, linux server deploy, doc and dependency update
test / test (push) Canceled after 0s
test / test (push) Canceled after 0s
This commit is contained in:
1 parent
52ac0fe31a
commit
f1ac4cbbe7
71 files changed
+7677
-537
No files matched your search
@@ -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()
|
||||
|
||||
Reference in new issue
Block a user