강동현

방 입장, 퇴장 구현

import { Socket } from "socket.io";
import { MessageHandlerRegistry } from "../message/MessageHandlerRegistry";
import { Message } from "../message/types";
import { Room } from "../room/Room";
import { User } from "../user/User";
export class Connection {
public readonly socket: Socket;
public user?: User;
public room?: Room;
constructor(socket: Socket) {
this.socket = socket;
......@@ -16,4 +19,8 @@ export class Connection {
public get authenticated(): boolean {
return this.user !== undefined;
}
public send(message: Message) {
this.socket.emit(message.type, message);
}
}
......
......@@ -2,6 +2,7 @@ import express from "express";
import socketIo from "socket.io";
import { createServer } from "http";
import { SocketHandler } from "./SocketHandler";
import { RoomManager } from "./room/RoomManager";
const PORT = 3000;
......@@ -10,6 +11,7 @@ const server = createServer(app);
const io = new socketIo.Server(server);
const handler = new SocketHandler();
const roomManager = new RoomManager();
io.on("connection", (socket) => {
handler.connected(socket);
......
import { Connection } from "../connection/Connection";
import { loginHandler } from "./handler/loginHandler";
import { MessageType } from "./types";
import { roomJoinHandler } from "./handler/roomJoinHandler";
import { roomLeaveHandler } from "./handler/roomLeaveHandler";
import { Message, MessageType } from "./types";
export class MessageHandlerRegistry {
static registerHandlers(connection: Connection) {
this.registerHandler(connection, MessageType.LOGIN, loginHandler);
this.registerHandler(connection, MessageType.ROOM_JOIN, roomJoinHandler);
this.registerHandler(connection, MessageType.ROOM_LEAVE, roomLeaveHandler);
}
private static registerHandler<T>(
private static registerHandler<T extends Message>(
connection: Connection,
typeName: string,
handler: (connection: Connection, message: T) => void
......
import { Connection } from "../../connection/Connection";
import { RoomManager } from "../../room/RoomManager";
import { User } from "../../user/User";
import { LoginMessage } from "../types";
......@@ -8,4 +9,6 @@ export function loginHandler(
): void {
connection.user = new User(message.username);
console.log(`User ${message.username} has logged in!`);
RoomManager.instance().sendList(connection);
}
......
import { Connection } from "../../connection/Connection";
import { RoomManager } from "../../room/RoomManager";
import { RoomJoinMessage } from "../types";
export function roomJoinHandler(
connection: Connection,
message: RoomJoinMessage
): void {
const room = RoomManager.instance().get(message.uuid);
if (room !== undefined) {
room.connect(connection);
}
}
import { Connection } from "../../connection/Connection";
import { RoomManager } from "../../room/RoomManager";
import { RoomLeaveMessage } from "../types";
export function roomLeaveHandler(
connection: Connection,
message: RoomLeaveMessage
): void {
if (connection.room !== undefined) {
connection.room.disconnect(connection);
}
}
export interface LoginMessage {
username: string;
import { RoomData } from "../room/types";
export interface Message {
readonly type: string;
}
export class LoginMessage implements Message {
readonly type = MessageType.LOGIN;
constructor(public username: string) {}
}
export class RoomListMessage implements Message {
readonly type = MessageType.ROOM_LIST;
constructor(public rooms: RoomData[]) {}
}
export class RoomJoinMessage implements Message {
readonly type = MessageType.ROOM_JOIN;
constructor(public uuid: string) {}
}
export class RoomLeaveMessage implements Message {
readonly type = MessageType.ROOM_LEAVE;
constructor() {}
}
export class MessageType {
static readonly LOGIN = "login";
static readonly ROOM_LIST = "room_list";
static readonly ROOM_JOIN = "room_join";
static readonly ROOM_LEAVE = "room_leave";
}
......
import { Connection } from "../connection/Connection";
import { v4 as uuidv4 } from "uuid";
import { RoomData } from "./types";
export class Room {
public readonly uuid: string;
......@@ -26,18 +27,29 @@ export class Room {
}
this.connections.push(connection);
connection.room = this; // TODO: 더 나은 관리
}
public disconnect(connection: Connection): void {
const index = this.connections.indexOf(connection);
if (index > -1) {
this.connections.splice(index, 1);
connection.room = undefined;
}
}
public getData(): RoomData {
return {
uuid: this.uuid,
name: this.name,
currentConnections: this.connections.length,
maxConnections: this.maxConnections,
};
}
public close(): void {
if (!this.closed) {
// TODO
this.connections.forEach((connection) => this.disconnect(connection));
this.closed = true;
}
}
......
import { Connection } from "../connection/Connection";
import { RoomListMessage } from "../message/types";
import { Room } from "./Room";
import { RoomData } from "./types";
export class RoomManager {
private static _instance: RoomManager;
private rooms: Map<string, Room>;
constructor() {
RoomManager._instance = this;
this.rooms = new Map<string, Room>();
}
public static instance(): RoomManager {
return RoomManager._instance;
}
public create(name: string, maxConnections: number): Room {
const room = new Room(name, maxConnections);
this.rooms.set(name, room);
......@@ -24,4 +34,13 @@ export class RoomManager {
this.rooms.delete(uuid);
}
}
public sendList(connection: Connection): void {
var roomData: RoomData[] = [];
this.rooms.forEach((room) => {
roomData.push(room.getData());
});
connection.send(new RoomListMessage(roomData));
}
}
......
export interface RoomData {
uuid: string;
name: string;
currentConnections: number;
maxConnections: number;
}