Files
gomoku/server/database/cleanup.go
T
tiennm99 acf08669dd feat(database): new domain model for PVP/PVE/spectator with thread-safe store
- Split monolithic database.go/model.go/gomoku.go into focused files:
  player.go, room.go, store.go, errors.go, events.go, cleanup.go
- NewRoom embeds game.Board directly; carries blackPlayerId, whitePlayerId,
  currentTurn, moveHistory, spectators, owner, type, difficulty from caro domain
- Store singleton with sync.RWMutex: RegisterPlayer, CreatePvpRoom, CreatePveRoom,
  JoinNewRoom, LeaveNewRoom, WatchNewRoom, UnwatchNewRoom, BroadcastToNewRoom
- PVE rooms randomly assign human to Black or White; AI takes opposite side
- legacy.go shim keeps server/state/*.go and state/game/gomoku.go compiling
  without modification until phase-06 rewrites them
- consts/const.go: add RoomTypePvp/Pve, Status*, RoomStatus*, Difficulty* enums
2026-04-11 13:30:58 +07:00

46 lines
1.1 KiB
Go

package database
import (
"time"
"github.com/tiennm99/gomoku/server/pkg/log"
)
const idleRoomTimeout = 5 * time.Minute
// StartCleanup launches the idle-room reaper goroutine.
// Called once from main.go during server startup.
// Rooms with no active players and no spectators for longer than idleRoomTimeout are deleted.
func StartCleanup() {
go runCleanupLoop()
}
func runCleanupLoop() {
ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop()
for range ticker.C {
reapIdleRooms()
}
}
// reapIdleRooms scans all new-domain rooms and removes those that have been
// idle (no players, no spectators) for longer than idleRoomTimeout.
func reapIdleRooms() {
rooms := GetAllRooms()
for _, r := range rooms {
r.RLock()
nPlayers := len(r.Players)
nSpectators := len(r.Spectators)
lastActive := r.LastActive
id := r.ID
r.RUnlock()
if nPlayers == 0 && nSpectators == 0 && time.Since(lastActive) > idleRoomTimeout {
log.Infof("[cleanup] removing idle room %d (no activity for >%s)\n", id, idleRoomTimeout)
store.mu.Lock()
deleteNewRoom(id)
store.mu.Unlock()
}
}
}