mirror of
https://github.com/randyjc/Rahoot.git
synced 2026-03-13 20:15:35 +01:00
Initial clean state
This commit is contained in:
165
packages/socket/src/services/registry.ts
Normal file
165
packages/socket/src/services/registry.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
import Game from "@rahoot/socket/services/game"
|
||||
import dayjs from "dayjs"
|
||||
|
||||
interface EmptyGame {
|
||||
since: number
|
||||
game: Game
|
||||
}
|
||||
|
||||
class Registry {
|
||||
private static instance: Registry | null = null
|
||||
private games: Game[] = []
|
||||
private emptyGames: EmptyGame[] = []
|
||||
private cleanupInterval: ReturnType<typeof setTimeout> | null = null
|
||||
private readonly EMPTY_GAME_TIMEOUT_MINUTES = 5
|
||||
private readonly CLEANUP_INTERVAL_MS = 60_000
|
||||
|
||||
private constructor() {
|
||||
this.startCleanupTask()
|
||||
}
|
||||
|
||||
static getInstance(): Registry {
|
||||
Registry.instance ||= new Registry()
|
||||
|
||||
return Registry.instance
|
||||
}
|
||||
|
||||
addGame(game: Game): void {
|
||||
this.games.push(game)
|
||||
console.log(`Game ${game.gameId} added. Total games: ${this.games.length}`)
|
||||
}
|
||||
|
||||
getGameById(gameId: string): Game | undefined {
|
||||
return this.games.find((g) => g.gameId === gameId)
|
||||
}
|
||||
|
||||
getGameByInviteCode(inviteCode: string): Game | undefined {
|
||||
return this.games.find((g) => g.inviteCode === inviteCode)
|
||||
}
|
||||
|
||||
getPlayerGame(gameId: string, clientId: string): Game | undefined {
|
||||
return this.games.find(
|
||||
(g) =>
|
||||
g.gameId === gameId && g.players.some((p) => p.clientId === clientId)
|
||||
)
|
||||
}
|
||||
|
||||
getManagerGame(gmageId: string, clientId: string): Game | undefined {
|
||||
return this.games.find(
|
||||
(g) => g.gameId === gmageId && g.manager.clientId === clientId
|
||||
)
|
||||
}
|
||||
|
||||
getGameByManagerSocketId(socketId: string): Game | undefined {
|
||||
return this.games.find((g) => g.manager.id === socketId)
|
||||
}
|
||||
|
||||
getGameByPlayerSocketId(socketId: string): Game | undefined {
|
||||
return this.games.find((g) => g.players.some((p) => p.id === socketId))
|
||||
}
|
||||
|
||||
markGameAsEmpty(game: Game): void {
|
||||
const alreadyEmpty = this.emptyGames.find(
|
||||
(g) => g.game.gameId === game.gameId
|
||||
)
|
||||
|
||||
if (!alreadyEmpty) {
|
||||
this.emptyGames.push({
|
||||
since: dayjs().unix(),
|
||||
game,
|
||||
})
|
||||
console.log(
|
||||
`Game ${game.gameId} marked as empty. Total empty games: ${this.emptyGames.length}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
reactivateGame(gameId: string): void {
|
||||
const initialLength = this.emptyGames.length
|
||||
this.emptyGames = this.emptyGames.filter((g) => g.game.gameId !== gameId)
|
||||
|
||||
if (this.emptyGames.length < initialLength) {
|
||||
console.log(
|
||||
`Game ${gameId} reactivated. Remaining empty games: ${this.emptyGames.length}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
removeGame(gameId: string): boolean {
|
||||
const game = this.games.find((g) => g.gameId === gameId)
|
||||
void game?.clearPersisted?.()
|
||||
|
||||
const initialLength = this.games.length
|
||||
this.games = this.games.filter((g) => g.gameId !== gameId)
|
||||
this.emptyGames = this.emptyGames.filter((g) => g.game.gameId !== gameId)
|
||||
|
||||
const removed = this.games.length < initialLength
|
||||
|
||||
if (removed) {
|
||||
console.log(`Game ${gameId} removed. Total games: ${this.games.length}`)
|
||||
}
|
||||
|
||||
return removed
|
||||
}
|
||||
|
||||
getAllGames(): Game[] {
|
||||
return [...this.games]
|
||||
}
|
||||
|
||||
getGameCount(): number {
|
||||
return this.games.length
|
||||
}
|
||||
|
||||
getEmptyGameCount(): number {
|
||||
return this.emptyGames.length
|
||||
}
|
||||
|
||||
private cleanupEmptyGames(): void {
|
||||
const now = dayjs()
|
||||
const stillEmpty = this.emptyGames.filter(
|
||||
(g) =>
|
||||
now.diff(dayjs.unix(g.since), "minute") <
|
||||
this.EMPTY_GAME_TIMEOUT_MINUTES
|
||||
)
|
||||
|
||||
if (stillEmpty.length === this.emptyGames.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const removed = this.emptyGames.filter((g) => !stillEmpty.includes(g))
|
||||
const removedGameIds = removed.map((r) => r.game.gameId)
|
||||
removed.forEach((entry) => void entry.game.clearPersisted?.())
|
||||
|
||||
this.games = this.games.filter((g) => !removedGameIds.includes(g.gameId))
|
||||
this.emptyGames = stillEmpty
|
||||
|
||||
console.log(
|
||||
`Removed ${removed.length} empty game(s). Remaining games: ${this.games.length}`
|
||||
)
|
||||
}
|
||||
|
||||
private startCleanupTask(): void {
|
||||
this.cleanupInterval = setInterval(() => {
|
||||
this.cleanupEmptyGames()
|
||||
}, this.CLEANUP_INTERVAL_MS)
|
||||
|
||||
console.log("Game cleanup task started")
|
||||
}
|
||||
|
||||
stopCleanupTask(): void {
|
||||
if (this.cleanupInterval) {
|
||||
clearInterval(this.cleanupInterval)
|
||||
this.cleanupInterval = null
|
||||
console.log("Game cleanup task stopped")
|
||||
}
|
||||
}
|
||||
|
||||
cleanup(): void {
|
||||
this.stopCleanupTask()
|
||||
this.games = []
|
||||
this.emptyGames = []
|
||||
console.log("Registry cleaned up")
|
||||
}
|
||||
}
|
||||
|
||||
export default Registry
|
||||
Reference in New Issue
Block a user