Connection.ts 2.04 KB
import { Socket } from "socket.io";
import {
  RawMessage,
  ServerInboundMessage,
  ServerInboundMessageKey,
  ServerOutboundMessage,
  ServerOutboundMessageKey,
  ServerResponse,
} from "../../common";
import { Room } from "../room/Room";
import { RoomManager } from "../room/RoomManager";
import { User } from "../user/User";
import { MessageValidator } from "./MessageValidator";
import { SocketWrapper } from "./SocketWrapper";

export class Connection {
  public readonly socket: SocketWrapper;
  public readonly roomManager: RoomManager;

  static readonly validator: MessageValidator = new MessageValidator();

  public user?: User;

  constructor(socket: SocketWrapper, roomManager: RoomManager) {
    this.socket = socket;
    this.roomManager = roomManager;
    socket.setHandler((raw) => this.handleRaw(raw));
  }

  public send<T extends ServerOutboundMessageKey>(
    type: T,
    message: ServerOutboundMessage<T>
  ) {
    this.socket.send({
      type: type as string,
      message: message,
    });
  }

  public handleRaw(raw: RawMessage): ServerResponse<any> {
    if (!raw || !raw.message || !raw.type) {
      return { ok: false };
    }
    const type = raw.type as ServerInboundMessageKey;
    const message = raw.message;

    if (!Connection.validator.validate(type, message)) {
      return { ok: false };
    }

    // 유저 정보가 없으므로 로그인은 따로 핸들링
    if (type === "login") {
      return this.handleLogin(message);
    }

    // Game > Room > User 순으로 전달
    if (this.user?.room) {
      const response = this.user.room.handler.handle(type, this.user, message);
      if (response) return response;
    }
    if (this.user) {
      const response = this.user.handler.handle(type, this.user, message);
      if (response) return response;
    }
    return { ok: false };
  }

  private handleLogin(
    message: ServerInboundMessage<"login">
  ): ServerResponse<"login"> {
    this.user = new User(message.username, this);
    // console.log(`User ${message.username} has logged in!`);

    return { ok: true };
  }
}