Newer
Older
PixelPaintWar / apps / server / src / network / handlers / room / registerRoomHandlers.ts
/**
 * registerRoomHandlers
 * ルーム参加イベントの受信ハンドラを登録する
 */
import { Socket } from "socket.io";
import { contracts as protocol } from "@repo/shared";
import type {
  JoinRoomEventRoomUseCasePort,
  JoinRoomEventRuntimeUseCasePort,
  LobbySettingsUpdateEventRoomUseCasePort,
} from "@server/network/types/connectionPorts";
import { createSocketRegistrationContext } from "@server/network/handlers/registration";
import {
  isJoinRoomPayload,
  isLobbySettingsUpdatePayload,
} from "@server/network/validation/socketPayloadValidators";
import type { RoomOutputAdapter } from "./createRoomOutputAdapter";
import {
  handleJoinRoomEvent,
  handleLobbySettingsUpdateEvent,
  type JoinRoomEventPayload,
  type JoinRoomOrchestratorDeps,
  type LobbySettingsUpdateOrchestratorDeps,
} from "./roomEventOrchestrators";
import {
  registerGuardedEvent,
  type GuardedEventDefinition,
} from "@server/network/handlers/eventDefinitionRegistrar";

type RoomHandlerRoomUseCasePort = JoinRoomEventRoomUseCasePort & LobbySettingsUpdateEventRoomUseCasePort;

type JoinRoomEventDefinition = GuardedEventDefinition<
  typeof protocol.SocketEvents.JOIN_ROOM,
  JoinRoomEventPayload
>;

type LobbySettingsUpdateEventDefinition = GuardedEventDefinition<
  typeof protocol.SocketEvents.LOBBY_SETTINGS_UPDATE,
  LobbySettingsUpdateOrchestratorDeps["roomManager"] extends infer _ ? Parameters<typeof handleLobbySettingsUpdateEvent>[1] : never
>;

/** ルームイベント調停で利用する依存束を生成する */
const createJoinRoomOrchestratorDeps = (
  socket: Socket,
  roomManager: JoinRoomEventRoomUseCasePort,
  runtimeRegistry: JoinRoomEventRuntimeUseCasePort,
  roomOutputAdapter: RoomOutputAdapter,
): JoinRoomOrchestratorDeps => {
  return {
    socketId: socket.id,
    roomManager,
    runtimeRegistry,
    output: roomOutputAdapter,
    joinRoom: async (roomId) => {
      await socket.join(roomId);
    },
  };
};

/** ロビー設定更新イベント調停で利用する依存束を生成する */
const createLobbySettingsUpdateOrchestratorDeps = (
  socket: Socket,
  roomManager: LobbySettingsUpdateEventRoomUseCasePort,
  roomOutputAdapter: RoomOutputAdapter,
): LobbySettingsUpdateOrchestratorDeps => {
  return {
    socketId: socket.id,
    roomManager,
    output: roomOutputAdapter,
  };
};

/** JOIN_ROOMイベント定義を生成する */
const createJoinRoomEventDefinition = (
  deps: JoinRoomOrchestratorDeps,
): JoinRoomEventDefinition => {
  return {
    event: protocol.SocketEvents.JOIN_ROOM,
    validator: isJoinRoomPayload,
    orchestrate: async (payload) => {
      await handleJoinRoomEvent(deps, payload);
    },
  };
};

/** LOBBY_SETTINGS_UPDATEイベント定義を生成する */
const createLobbySettingsUpdateEventDefinition = (
  deps: LobbySettingsUpdateOrchestratorDeps,
): LobbySettingsUpdateEventDefinition => {
  return {
    event: protocol.SocketEvents.LOBBY_SETTINGS_UPDATE,
    validator: isLobbySettingsUpdatePayload,
    orchestrate: (payload) => {
      handleLobbySettingsUpdateEvent(deps, payload);
    },
  };
};

/** ルーム関連イベントを検証してユースケースへ連携する */
export const registerRoomHandlers = (
  socket: Socket,
  roomManager: RoomHandlerRoomUseCasePort,
  runtimeRegistry: JoinRoomEventRuntimeUseCasePort,
  roomOutputAdapter: RoomOutputAdapter,
) => {
  const { onEvent, guardOnEvent } = createSocketRegistrationContext(socket);

  const joinRoomDeps = createJoinRoomOrchestratorDeps(
    socket,
    roomManager,
    runtimeRegistry,
    roomOutputAdapter,
  );
  const lobbySettingsDeps = createLobbySettingsUpdateOrchestratorDeps(
    socket,
    roomManager,
    roomOutputAdapter,
  );

  registerGuardedEvent(onEvent, guardOnEvent, createJoinRoomEventDefinition(joinRoomDeps));
  registerGuardedEvent(onEvent, guardOnEvent, createLobbySettingsUpdateEventDefinition(lobbySettingsDeps));
};