diff --git a/apps/server/src/network/handlers/game/registerGameHandlers.ts b/apps/server/src/network/handlers/game/registerGameHandlers.ts index 30840a8..b7bd305 100644 --- a/apps/server/src/network/handlers/game/registerGameHandlers.ts +++ b/apps/server/src/network/handlers/game/registerGameHandlers.ts @@ -37,11 +37,19 @@ const common = createCommonHandlerContext(io, socket); const gameOutputAdapter = createGameOutputAdapter(common); const { onEvent } = createServerSocketOnBridge(socket); - const payloadGuard = createPayloadGuard(socket.id); + const { guardOnEvent } = createPayloadGuard(socket.id); + const guardPingPayload = guardOnEvent( + protocol.SocketEvents.PING, + gamePayloadValidators[protocol.SocketEvents.PING] + ); + const guardMovePayload = guardOnEvent( + protocol.SocketEvents.MOVE, + gamePayloadValidators[protocol.SocketEvents.MOVE] + ); // 遅延計測用のPINGを検証しPONGを返す onEvent(protocol.SocketEvents.PING, (clientTime) => { - if (!payloadGuard(protocol.SocketEvents.PING, clientTime, gamePayloadValidators[protocol.SocketEvents.PING])) { + if (!guardPingPayload(clientTime)) { return; } @@ -73,7 +81,7 @@ // 移動入力を検証しプレイヤー移動ユースケースへ連携する onEvent(protocol.SocketEvents.MOVE, (data) => { - if (!payloadGuard(protocol.SocketEvents.MOVE, data, gamePayloadValidators[protocol.SocketEvents.MOVE])) { + if (!guardMovePayload(data)) { return; } diff --git a/apps/server/src/network/handlers/payloadGuard.ts b/apps/server/src/network/handlers/payloadGuard.ts index 6b75872..474bde1 100644 --- a/apps/server/src/network/handlers/payloadGuard.ts +++ b/apps/server/src/network/handlers/payloadGuard.ts @@ -7,12 +7,13 @@ type PayloadValidator = (value: unknown) => value is TPayload; type SocketEventName = (typeof protocol.SocketEvents)[keyof typeof protocol.SocketEvents]; +type EventBoundPayloadGuard = (payload: unknown) => payload is TPayload; /** * 受信ペイロードを検証し,不正時は共通ログを記録するガード関数を生成する */ export const createPayloadGuard = (socketId: string) => { - return ( + const isValidPayload = ( event: SocketEventName, payload: unknown, validator: PayloadValidator @@ -29,4 +30,18 @@ return false; }; + + const guardOnEvent = ( + event: SocketEventName, + validator: PayloadValidator + ): EventBoundPayloadGuard => { + return (payload: unknown): payload is TPayload => { + return isValidPayload(event, payload, validator); + }; + }; + + return { + isValidPayload, + guardOnEvent, + }; }; diff --git a/apps/server/src/network/handlers/room/registerRoomHandlers.ts b/apps/server/src/network/handlers/room/registerRoomHandlers.ts index d285330..4d7847a 100644 --- a/apps/server/src/network/handlers/room/registerRoomHandlers.ts +++ b/apps/server/src/network/handlers/room/registerRoomHandlers.ts @@ -27,11 +27,15 @@ const common = createCommonHandlerContext(io, socket); const roomOutputAdapter = createRoomOutputAdapter(common); const { onEvent } = createServerSocketOnBridge(socket); - const payloadGuard = createPayloadGuard(socket.id); + const { guardOnEvent } = createPayloadGuard(socket.id); + const guardJoinRoomPayload = guardOnEvent( + protocol.SocketEvents.JOIN_ROOM, + roomPayloadValidators[protocol.SocketEvents.JOIN_ROOM] + ); // 参加要求のペイロード検証と参加処理を実行する onEvent(protocol.SocketEvents.JOIN_ROOM, async (data) => { - if (!payloadGuard(protocol.SocketEvents.JOIN_ROOM, data, roomPayloadValidators[protocol.SocketEvents.JOIN_ROOM])) { + if (!guardJoinRoomPayload(data)) { return; } diff --git a/apps/server/src/network/handlers/socketEventBridge.ts b/apps/server/src/network/handlers/socketEventBridge.ts index b14bc41..977ef98 100644 --- a/apps/server/src/network/handlers/socketEventBridge.ts +++ b/apps/server/src/network/handlers/socketEventBridge.ts @@ -7,19 +7,13 @@ import { createSocketEventBridge, type ClientToServerEventPayloadMap, + type SocketBridgeTarget, type ServerToClientEventPayloadMap, } from "@repo/shared"; -type BridgeTarget = { - on: (event: string, callback: (payload: unknown) => void) => void; - once: (event: string, callback: (payload: unknown) => void) => void; - off: (event: string, callback: (payload: unknown) => void) => void; - emit: (event: string, payload?: unknown) => void; -}; - /** サーバー向けの型付きソケットイベント bridge を生成する */ export const createServerSocketOnBridge = (socket: Socket) => { - const bridgeTarget: BridgeTarget = { + const bridgeTarget: SocketBridgeTarget = { on: (event, callback) => { socket.on(event, callback); }, diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index f7973ac..1b3fd0f 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -41,5 +41,7 @@ } from "./protocol/events"; /** ソケットイベントブリッジ生成関数を再公開 */ export { createSocketEventBridge } from "./protocol/socketEventBridge"; +/** ソケットイベントブリッジ生成に必要な最小インターフェースを再公開 */ +export type { SocketBridgeTarget } from "./protocol/socketEventBridge"; /** 共有設定値を再公開 */ export * as config from "./config"; \ No newline at end of file diff --git a/packages/shared/src/protocol/socketEventBridge.ts b/packages/shared/src/protocol/socketEventBridge.ts index f171a3f..a5f61e2 100644 --- a/packages/shared/src/protocol/socketEventBridge.ts +++ b/packages/shared/src/protocol/socketEventBridge.ts @@ -1,8 +1,13 @@ +/** + * socketEventBridge + * ソケットイベントの受信購読と送信を型安全に橋渡しする共通ブリッジを提供する + */ type EventPayloadMap = Record; type EventNameOf = Extract; -type SocketBridgeTarget = { +/** ソケットブリッジ生成に必要な最小インターフェース */ +export type SocketBridgeTarget = { on: (event: string, callback: (payload: unknown) => void) => void; once: (event: string, callback: (payload: unknown) => void) => void; off: (event: string, callback: (payload: unknown) => void) => void; @@ -10,7 +15,7 @@ }; /** - * 受信・送信イベントの型マップを指定して、Socket.IOブリッジを生成する + * 受信・送信イベントの型マップを指定して,Socket.IOブリッジを生成する */ export const createSocketEventBridge = < TInboundMap extends EventPayloadMap, @@ -20,32 +25,32 @@ event: TEvent, callback: (payload: TInboundMap[TEvent]) => void ) => { - (socket as any).on(event, callback); + socket.on(event, callback as (payload: unknown) => void); }; const onceEvent = >( event: TEvent, callback: (payload: TInboundMap[TEvent]) => void ) => { - (socket as any).once(event, callback); + socket.once(event, callback as (payload: unknown) => void); }; const offEvent = >( event: TEvent, callback: (payload: TInboundMap[TEvent]) => void ) => { - (socket as any).off(event, callback); + socket.off(event, callback as (payload: unknown) => void); }; function emitEvent>(event: TEvent): void; function emitEvent>(event: TEvent, payload: TOutboundMap[TEvent]): void; function emitEvent>(event: TEvent, payload?: TOutboundMap[TEvent]): void { if (payload === undefined) { - (socket as any).emit(event); + socket.emit(event); return; } - (socket as any).emit(event, payload); + socket.emit(event, payload as unknown); } return {