Newer
Older
PixelPaintWar / apps / server / src / network / handlers / registerConnectionHandlers.ts
/**
 * registerConnectionHandlers
 * 接続時にルームとゲームの各ハンドラを登録する
 */
import { Server, Socket } from "socket.io";
import { protocol } from "@repo/shared";
import { disconnectCoordinator } from "@server/application/coordinators/disconnectCoordinator";
import { registerGameHandlers } from "./GameHandler";
import { registerRoomHandlers } from "./RoomHandler";
import {
  createDisconnectOutputAdapters,
  createSocketOutputAdapters,
} from "./createOutputAdapters";
import { logConnected, logDisconnected } from "./connectionEventLogger";
import {
  registerEvents,
  registerUnguardedEvents,
  type EventDefinition,
  type UnguardedEventDefinition,
} from "./eventDefinitionRegistrar";
import type {
  RegisterConnectionHandlersParams,
} from "../types/connectionPorts";

/** 接続イベント調停で利用する依存束 */
type ConnectionHandlerDeps = {
  io: Server;
  socket: Socket;
} & Omit<RegisterConnectionHandlersParams, "io">;

/** 接続ハンドラで利用する依存束を生成する */
const createConnectionHandlerDeps = (
  params: RegisterConnectionHandlersParams,
  socket: Socket,
): ConnectionHandlerDeps => {
  return {
    io: params.io,
    socket,
    roomManager: params.roomManager,
    runtimeRegistry: params.runtimeRegistry,
  };
};

/** ソケット接続と切断イベントに対する共通ハンドラを登録する */
export const registerConnectionHandlers = ({
  io,
  roomManager,
  runtimeRegistry,
}: RegisterConnectionHandlersParams) => {
  const disconnectOutputAdapters = createDisconnectOutputAdapters(io);

  // CONNECTイベントを宣言的に登録する
  const onConnectEventDefinitions: EventDefinition<
    typeof protocol.SocketEvents.CONNECT,
    Socket
  >[] = [
    {
      event: protocol.SocketEvents.CONNECT,
      orchestrate: (socket) => {
        const deps = createConnectionHandlerDeps(
          {
            io,
            roomManager,
            runtimeRegistry,
          },
          socket,
        );
        const socketOutputAdapters = createSocketOutputAdapters(deps.io, deps.socket);

        // 接続ログを記録してドメイン別ハンドラを登録する
        logConnected(deps.socket.id);

        registerRoomHandlers(
          deps.socket,
          deps.roomManager,
          deps.runtimeRegistry,
          socketOutputAdapters.room,
        );
        registerGameHandlers(
          deps.socket,
          deps.roomManager,
          deps.runtimeRegistry,
          socketOutputAdapters.game,
        );

        // ソケット単位イベントを宣言的に登録する
        const perSocketEventDefinitions: UnguardedEventDefinition<
          typeof protocol.SocketEvents.DISCONNECT
        >[] = [
          {
            event: protocol.SocketEvents.DISCONNECT,
            orchestrate: () => {
              // 切断ログ記録後にドメイン別の後処理を実行する
              logDisconnected(deps.socket.id);

              disconnectCoordinator({
                socketId: deps.socket.id,
                roomManager: deps.roomManager,
                runtimeRegistry: deps.runtimeRegistry,
                gameOutput: disconnectOutputAdapters.game,
                roomOutput: disconnectOutputAdapters.room,
              });
            },
          },
        ];

        registerUnguardedEvents(
          (event, callback) => {
            deps.socket.on(event, callback);
          },
          perSocketEventDefinitions,
        );
      },
    },
  ];

  registerEvents(
    (event, callback) => {
      io.on(event, (socket) => {
        callback(socket);
      });
    },
    onConnectEventDefinitions,
  );
};