diff --git a/apps/server/src/application/coordinators/disconnectCoordinator.ts b/apps/server/src/application/coordinators/disconnectCoordinator.ts index 739dee6..fdcfc85 100644 --- a/apps/server/src/application/coordinators/disconnectCoordinator.ts +++ b/apps/server/src/application/coordinators/disconnectCoordinator.ts @@ -6,21 +6,13 @@ type GameOutputPort, } from "@server/domains/game/application/ports/gameUseCasePorts"; import type { - CleanupGameRuntimePort, - DisconnectRoomPort, - FindGameByPlayerPort, - FindRoomByIdPort, - FindRoomByPlayerPort, + DisconnectDeps, RoomOutputPort, } from "@server/domains/room/application/ports/roomUseCasePorts"; +import { resolveRuntimeByPlayerId } from "@server/domains/room/application/services/RoomRuntimeResolver"; import { disconnectUseCase } from "@server/domains/game/application/useCases/disconnectUseCase"; import { roomDisconnectUseCase } from "@server/domains/room/application/useCases/roomDisconnectUseCase"; -type DisconnectDeps = { - roomManager: DisconnectRoomPort & FindRoomByPlayerPort & FindRoomByIdPort; - runtimeRegistry: FindGameByPlayerPort & CleanupGameRuntimePort; -}; - /** 切断調停で利用する入力ポートと出力ポートの契約 */ export type DisconnectCoordinatorParams = { socketId: string; @@ -37,13 +29,12 @@ gameOutput, roomOutput, }: DisconnectCoordinatorParams) => { - const roomId = roomManager.getRoomByPlayerId(socketId)?.roomId; - const gameManager = runtimeRegistry.getGameManagerByPlayerId(socketId); + const runtime = resolveRuntimeByPlayerId(roomManager, runtimeRegistry, socketId); - if (gameManager) { + if (runtime) { disconnectUseCase({ - gameManager, - roomId, + gameManager: runtime.gameManager, + roomId: runtime.roomId, playerId: socketId, output: gameOutput, }); diff --git a/apps/server/src/application/coordinators/readyForGameCoordinator.ts b/apps/server/src/application/coordinators/readyForGameCoordinator.ts index 19fbd7c..68d8f44 100644 --- a/apps/server/src/application/coordinators/readyForGameCoordinator.ts +++ b/apps/server/src/application/coordinators/readyForGameCoordinator.ts @@ -5,14 +5,10 @@ import { type GameOutputPort, } from "@server/domains/game/application/ports/gameUseCasePorts"; -import type { FindGameByPlayerPort, FindRoomByPlayerPort } from "@server/domains/room/application/ports/roomUseCasePorts"; +import type { ReadyForGameDeps } from "@server/domains/room/application/ports/roomUseCasePorts"; +import { resolveRuntimeByPlayerId } from "@server/domains/room/application/services/RoomRuntimeResolver"; import { readyForGameUseCase } from "@server/domains/game/application/useCases/readyForGameUseCase"; -type ReadyForGameDeps = { - roomManager: FindRoomByPlayerPort; - runtimeRegistry: FindGameByPlayerPort; -}; - type ReadyForGameCoordinatorParams = { socketId: string; } & ReadyForGameDeps & { @@ -26,13 +22,12 @@ runtimeRegistry, output, }: ReadyForGameCoordinatorParams) => { - const room = roomManager.getRoomByPlayerId(socketId); - const gameManager = runtimeRegistry.getGameManagerByPlayerId(socketId); + const runtime = resolveRuntimeByPlayerId(roomManager, runtimeRegistry, socketId); readyForGameUseCase({ socketId, - roomId: room?.roomId, - gameManager, + roomId: runtime?.roomId, + gameManager: runtime?.gameManager, output, }); }; diff --git a/apps/server/src/application/coordinators/startGameCoordinator.ts b/apps/server/src/application/coordinators/startGameCoordinator.ts index d7c43e0..75198dd 100644 --- a/apps/server/src/application/coordinators/startGameCoordinator.ts +++ b/apps/server/src/application/coordinators/startGameCoordinator.ts @@ -6,20 +6,13 @@ type GameOutputPort, } from "@server/domains/game/application/ports/gameUseCasePorts"; import type { - FindGameByRoomPort, - FindRoomByOwnerPort, - RoomPhaseTransitionPort, + StartGameDeps, } from "@server/domains/room/application/ports/roomUseCasePorts"; import { startGameUseCase } from "@server/domains/game/application/useCases/startGameUseCase"; import { logEvent } from "@server/logging/logger"; import { gameUseCaseLogEvents, logResults, logScopes } from "@server/logging/index"; import { roomConsts } from "@repo/shared"; -type StartGameDeps = { - roomManager: FindRoomByOwnerPort & RoomPhaseTransitionPort; - runtimeRegistry: FindGameByRoomPort; -}; - type StartGameCoordinatorParams = { ownerId: string; } & StartGameDeps & { diff --git a/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts b/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts index e87f5b0..034ee0d 100644 --- a/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts +++ b/apps/server/src/domains/room/application/ports/roomUseCasePorts.ts @@ -11,6 +11,7 @@ StartGamePort, } from "@server/domains/game/application/ports/gameUseCasePorts"; +/** ルーム単位ゲーム管理が満たす操作ポート集合 */ export type RoomScopedGamePort = & StartGamePort & ReadyForGamePort @@ -68,7 +69,7 @@ /** ルーム解散後に不要ランタイムを破棄する操作ポート */ export interface CleanupGameRuntimePort { - cleanupDisposedRoomRuntimes(): void; + cleanupGameManagerForRoom(roomId: string): void; } /** ルームIDでゲーム管理を解決する参照ポート */ @@ -80,3 +81,21 @@ export interface FindGameByPlayerPort { getGameManagerByPlayerId(playerId: string): RoomScopedGamePort | undefined; } + +/** START_GAME調停で利用する依存集合 */ +export type StartGameDeps = { + roomManager: FindRoomByOwnerPort & RoomPhaseTransitionPort; + runtimeRegistry: FindGameByRoomPort; +}; + +/** READY_FOR_GAME調停で利用する依存集合 */ +export type ReadyForGameDeps = { + roomManager: FindRoomByPlayerPort; + runtimeRegistry: FindGameByPlayerPort; +}; + +/** DISCONNECT調停で利用する依存集合 */ +export type DisconnectDeps = { + roomManager: DisconnectRoomPort & FindRoomByPlayerPort & FindRoomByIdPort; + runtimeRegistry: FindGameByPlayerPort & CleanupGameRuntimePort; +}; diff --git a/apps/server/src/domains/room/application/services/RoomGameRuntimeRegistry.ts b/apps/server/src/domains/room/application/services/RoomGameRuntimeRegistry.ts index 390887f..20ca525 100644 --- a/apps/server/src/domains/room/application/services/RoomGameRuntimeRegistry.ts +++ b/apps/server/src/domains/room/application/services/RoomGameRuntimeRegistry.ts @@ -40,14 +40,17 @@ return this.gameManagers.get(roomId); } - public cleanupDisposedRoomRuntimes(): void { - for (const [roomId, gameManager] of this.gameManagers.entries()) { - if (this.roomResolver.getRoomById(roomId)) { - continue; - } - - gameManager.dispose(); - this.gameManagers.delete(roomId); + public cleanupGameManagerForRoom(roomId: string): void { + if (this.roomResolver.getRoomById(roomId)) { + return; } + + const gameManager = this.gameManagers.get(roomId); + if (!gameManager) { + return; + } + + gameManager.dispose(); + this.gameManagers.delete(roomId); } } diff --git a/apps/server/src/domains/room/application/services/RoomRuntimeResolver.ts b/apps/server/src/domains/room/application/services/RoomRuntimeResolver.ts new file mode 100644 index 0000000..85d3723 --- /dev/null +++ b/apps/server/src/domains/room/application/services/RoomRuntimeResolver.ts @@ -0,0 +1,33 @@ +/** + * RoomRuntimeResolver + * プレイヤーIDからルームIDとゲームランタイムを解決する + */ +import type { + FindGameByPlayerPort, + FindRoomByPlayerPort, + RoomScopedGamePort, +} from "../ports/roomUseCasePorts"; + +/** プレイヤー起点で解決したランタイム情報 */ +export type RuntimeByPlayerResolution = { + roomId: string; + gameManager: RoomScopedGamePort; +}; + +/** プレイヤーIDからルームIDとゲームランタイムを解決する */ +export const resolveRuntimeByPlayerId = ( + roomResolver: FindRoomByPlayerPort, + runtimeResolver: FindGameByPlayerPort, + playerId: string +): RuntimeByPlayerResolution | undefined => { + const roomId = roomResolver.getRoomByPlayerId(playerId)?.roomId; + const gameManager = runtimeResolver.getGameManagerByPlayerId(playerId); + if (!roomId || !gameManager) { + return undefined; + } + + return { + roomId, + gameManager, + }; +}; diff --git a/apps/server/src/domains/room/application/useCases/roomDisconnectUseCase.ts b/apps/server/src/domains/room/application/useCases/roomDisconnectUseCase.ts index 9d3c9ce..6c395ba 100644 --- a/apps/server/src/domains/room/application/useCases/roomDisconnectUseCase.ts +++ b/apps/server/src/domains/room/application/useCases/roomDisconnectUseCase.ts @@ -2,13 +2,18 @@ * roomDisconnectUseCase * 切断時のルーム退出処理と状態更新配信を行うユースケース */ -import type { CleanupGameRuntimePort, DisconnectRoomPort } from "../ports/roomUseCasePorts"; +import type { + CleanupGameRuntimePort, + DisconnectRoomPort, + FindRoomByIdPort, + FindRoomByPlayerPort, +} from "../ports/roomUseCasePorts"; import type { RoomOutputPort } from "../ports/roomUseCasePorts"; import { logEvent } from "@server/logging/logger"; import { logResults, logScopes, roomUseCaseLogEvents } from "@server/logging/index"; type RoomDisconnectUseCaseParams = { - roomManager: DisconnectRoomPort; + roomManager: DisconnectRoomPort & FindRoomByPlayerPort & FindRoomByIdPort; runtimeRegistry: CleanupGameRuntimePort; socketId: string; output: Pick; @@ -21,6 +26,7 @@ socketId, output, }: RoomDisconnectUseCaseParams) => { + const beforeRoomId = roomManager.getRoomByPlayerId(socketId)?.roomId; const updatedRooms = roomManager.removePlayer(socketId); logEvent(logScopes.ROOM_USE_CASE, { event: roomUseCaseLogEvents.DISCONNECT, @@ -41,5 +47,11 @@ }); }); - runtimeRegistry.cleanupDisposedRoomRuntimes(); + if (!beforeRoomId) { + return; + } + + if (!roomManager.getRoomById(beforeRoomId)) { + runtimeRegistry.cleanupGameManagerForRoom(beforeRoomId); + } }; diff --git a/apps/server/src/network/handlers/game/registerGameHandlers.ts b/apps/server/src/network/handlers/game/registerGameHandlers.ts index 97e40a9..83693f9 100644 --- a/apps/server/src/network/handlers/game/registerGameHandlers.ts +++ b/apps/server/src/network/handlers/game/registerGameHandlers.ts @@ -11,12 +11,12 @@ FindGameByPlayerPort, FindRoomByOwnerPort, FindRoomByPlayerPort, - RoomScopedGamePort, RoomPhaseTransitionPort, } from "@server/domains/room/application/ports/roomUseCasePorts"; import { movePlayerUseCase } from "@server/domains/game/application/useCases/movePlayerUseCase"; import { placeBombUseCase } from "@server/domains/game/application/useCases/placeBombUseCase"; import { pingUseCase } from "@server/domains/game/application/useCases/pingUseCase"; +import { resolveRuntimeByPlayerId } from "@server/domains/room/application/services/RoomRuntimeResolver"; import { createCommonHandlerContext } from "@server/network/handlers/CommonHandler"; import { isMovePayload, isPingPayload, isPlaceBombPayload } from "@server/network/validation/socketPayloadValidators"; import { createServerSocketOnBridge } from "@server/network/handlers/socketEventBridge"; @@ -30,28 +30,6 @@ [protocol.SocketEvents.PLACE_BOMB]: isPlaceBombPayload, } as const; -type RuntimeResolution = { - roomId: string; - gameManager: RoomScopedGamePort; -}; - -const resolveRuntimeBySocketId = ( - roomManager: FindRoomByPlayerPort, - runtimeRegistry: FindGameByPlayerPort, - socketId: string -): RuntimeResolution | undefined => { - const roomId = roomManager.getRoomByPlayerId(socketId)?.roomId; - const gameManager = runtimeRegistry.getGameManagerByPlayerId(socketId); - if (!roomId || !gameManager) { - return undefined; - } - - return { - roomId, - gameManager, - }; -}; - /** ゲームイベントの購読とユースケース呼び出しを設定する */ export const registerGameHandlers = ( io: Server, @@ -113,7 +91,7 @@ return; } - const runtime = resolveRuntimeBySocketId(roomManager, runtimeRegistry, socket.id); + const runtime = resolveRuntimeByPlayerId(roomManager, runtimeRegistry, socket.id); if (!runtime) { return; } @@ -131,7 +109,7 @@ return; } - const runtime = resolveRuntimeBySocketId(roomManager, runtimeRegistry, socket.id); + const runtime = resolveRuntimeByPlayerId(roomManager, runtimeRegistry, socket.id); if (!runtime) { return; } diff --git a/apps/server/src/network/types/connectionPorts.ts b/apps/server/src/network/types/connectionPorts.ts index ca79e45..dbaf4bc 100644 --- a/apps/server/src/network/types/connectionPorts.ts +++ b/apps/server/src/network/types/connectionPorts.ts @@ -5,6 +5,7 @@ import type { Server } from "socket.io"; import type { CleanupGameRuntimePort, + DisconnectDeps, DisconnectRoomPort, EnsureGameRuntimePort, FindGameByRoomPort, @@ -29,24 +30,6 @@ & FindGameByRoomPort & FindGameByPlayerPort; -/** START_GAME調停で利用する依存集合 */ -export type StartGameDeps = { - roomManager: FindRoomByOwnerPort & RoomPhaseTransitionPort; - runtimeRegistry: FindGameByRoomPort; -}; - -/** READY_FOR_GAME調停で利用する依存集合 */ -export type ReadyForGameDeps = { - roomManager: FindRoomByPlayerPort; - runtimeRegistry: FindGameByPlayerPort; -}; - -/** DISCONNECT調停で利用する依存集合 */ -export type DisconnectDeps = { - roomManager: DisconnectRoomPort & FindRoomByPlayerPort & FindRoomByIdPort; - runtimeRegistry: FindGameByPlayerPort & CleanupGameRuntimePort; -}; - /** ソケット接続全体で利用するルーム管理ポート集合 */ export type SocketConnectionRoomPort = & ConnectionRoomPort