강동현

방 입장, 퇴장 구현

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