Newer
Older
PixelPaintWar / apps / server / src / network / handlers / room / registerRoomHandlers.ts
/**
 * registerRoomHandlers
 * ルーム参加イベントの受信ハンドラを登録する
 */
import { Server, Socket } from "socket.io";
import type { JoinRoomPort } from "@server/domains/room/application/ports/roomUseCasePorts";
import { protocol } from "@repo/shared";
import { joinRoomUseCase } from "@server/domains/room/application/useCases/joinRoomUseCase";
import { createCommonHandlerContext } from "@server/network/handlers/CommonHandler";
import { createRoomOutputAdapter } from "./createRoomOutputAdapter";
import { isJoinRoomPayload } from "@server/network/validation/socketPayloadValidators";
import { logEvent } from "@server/logging/logEvent";

/** ルーム参加イベントを検証して参加ユースケースへ連携する */
export const registerRoomHandlers = (
  io: Server,
  socket: Socket,
  roomManager: JoinRoomPort
) => {
  const common = createCommonHandlerContext(io, socket);
  const roomOutputAdapter = createRoomOutputAdapter(common);

  // 参加要求のペイロード検証と参加処理を実行する
  socket.on(protocol.SocketEvents.JOIN_ROOM, async (data: unknown) => {
    if (!isJoinRoomPayload(data)) {
      logEvent("Network", {
        event: "JOIN_ROOM",
        result: "ignored_invalid_payload",
        socketId: socket.id,
      });
      return;
    }

    const { roomId } = data;

    const joinResult = joinRoomUseCase({
      roomManager,
      socketId: socket.id,
      data,
      output: roomOutputAdapter,
    });

    // 参加拒否時は理由を通知する
    switch (joinResult.status) {
      case "full":
        logEvent("Network", {
          event: "JOIN_ROOM",
          result: "rejected_room_full",
          roomId,
          socketId: socket.id,
        });
        return;

      case "duplicate":
        logEvent("Network", {
          event: "JOIN_ROOM",
          result: "rejected_duplicate",
          roomId,
          socketId: socket.id,
        });
        return;

      case "joined":
        await socket.join(roomId);
        roomOutputAdapter.publishRoomUpdateToRoom(roomId, joinResult.room);
        logEvent("RoomUseCase", {
          event: "ROOM_UPDATE",
          result: "emitted",
          roomId,
          socketId: socket.id,
          ownerId: joinResult.room.ownerId,
          totalPlayers: joinResult.room.players.length,
        });
        return;

      default:
        return;
    }
  });
};