Showing
10 changed files
with
80 additions
and
132 deletions
| 1 | import express from "express"; | 1 | import express from "express"; |
| 2 | import socketIo, { Server as IoServer } from "socket.io"; | 2 | import socketIo, { Server as IoServer } from "socket.io"; |
| 3 | import { createServer } from "http"; | 3 | import { createServer } from "http"; |
| 4 | -import { SocketHandler } from "./SocketHandler"; | ||
| 5 | import { RoomManager } from "./room/RoomManager"; | 4 | import { RoomManager } from "./room/RoomManager"; |
| 5 | +import { Connection } from "./connection/Connection"; | ||
| 6 | +import { SocketIoWrapper } from "./connection/SocketWrapper"; | ||
| 6 | 7 | ||
| 7 | export class Server { | 8 | export class Server { |
| 8 | public readonly port: number; | 9 | public readonly port: number; |
| ... | @@ -15,7 +16,6 @@ export class Server { | ... | @@ -15,7 +16,6 @@ export class Server { |
| 15 | const server = createServer(app); | 16 | const server = createServer(app); |
| 16 | this.io = new socketIo.Server(server); | 17 | this.io = new socketIo.Server(server); |
| 17 | 18 | ||
| 18 | - const handler = new SocketHandler(); | ||
| 19 | const roomManager = new RoomManager(); | 19 | const roomManager = new RoomManager(); |
| 20 | 20 | ||
| 21 | roomManager.create("테스트 방 #1", 8); | 21 | roomManager.create("테스트 방 #1", 8); |
| ... | @@ -23,7 +23,7 @@ export class Server { | ... | @@ -23,7 +23,7 @@ export class Server { |
| 23 | roomManager.create("테스트 방 #3", 2); | 23 | roomManager.create("테스트 방 #3", 2); |
| 24 | 24 | ||
| 25 | this.io.on("connection", (socket) => { | 25 | this.io.on("connection", (socket) => { |
| 26 | - handler.connected(socket); | 26 | + new Connection(new SocketIoWrapper(socket), roomManager); |
| 27 | }); | 27 | }); |
| 28 | 28 | ||
| 29 | server.listen(port, () => console.log(`Listening on ${port}`)); | 29 | server.listen(port, () => console.log(`Listening on ${port}`)); | ... | ... |
server/SocketHandler.ts
deleted
100644 → 0
| 1 | -import { Socket } from "socket.io"; | ||
| 2 | -import { ConnectionMapper } from "./connection/ConnectionMapper"; | ||
| 3 | - | ||
| 4 | -export class SocketHandler { | ||
| 5 | - private connectionMapper: ConnectionMapper; | ||
| 6 | - | ||
| 7 | - constructor() { | ||
| 8 | - this.connectionMapper = new ConnectionMapper(); | ||
| 9 | - } | ||
| 10 | - | ||
| 11 | - public connected(socket: Socket) { | ||
| 12 | - const connection = this.connectionMapper.get(socket); | ||
| 13 | - } | ||
| 14 | -} |
| 1 | import { Socket } from "socket.io"; | 1 | import { Socket } from "socket.io"; |
| 2 | -import { ServerOutboundMessage, ServerOutboundMessageKey } from "../../common"; | 2 | +import { |
| 3 | -import { MessageHandlerChain } from "../message/MessageHandlerChain"; | 3 | + RawMessage, |
| 4 | + ServerInboundMessage, | ||
| 5 | + ServerInboundMessageKey, | ||
| 6 | + ServerOutboundMessage, | ||
| 7 | + ServerOutboundMessageKey, | ||
| 8 | + ServerResponse, | ||
| 9 | +} from "../../common"; | ||
| 4 | import { Room } from "../room/Room"; | 10 | import { Room } from "../room/Room"; |
| 11 | +import { RoomManager } from "../room/RoomManager"; | ||
| 5 | import { User } from "../user/User"; | 12 | import { User } from "../user/User"; |
| 13 | +import { SocketWrapper } from "./SocketWrapper"; | ||
| 6 | 14 | ||
| 7 | export class Connection { | 15 | export class Connection { |
| 8 | - public readonly socket: Socket; | 16 | + public readonly socket: SocketWrapper; |
| 17 | + public readonly roomManager: RoomManager; | ||
| 9 | 18 | ||
| 10 | public user?: User; | 19 | public user?: User; |
| 11 | 20 | ||
| 12 | - private messageHandlerChain: MessageHandlerChain; | 21 | + constructor(socket: SocketWrapper, roomManager: RoomManager) { |
| 13 | - | ||
| 14 | - constructor(socket: Socket) { | ||
| 15 | this.socket = socket; | 22 | this.socket = socket; |
| 16 | - this.messageHandlerChain = new MessageHandlerChain(this); | 23 | + this.roomManager = roomManager; |
| 24 | + socket.setHandler((raw) => this.handleRaw(raw)); | ||
| 17 | } | 25 | } |
| 18 | 26 | ||
| 19 | public send<T extends ServerOutboundMessageKey>( | 27 | public send<T extends ServerOutboundMessageKey>( |
| 20 | type: T, | 28 | type: T, |
| 21 | message: ServerOutboundMessage<T> | 29 | message: ServerOutboundMessage<T> |
| 22 | ) { | 30 | ) { |
| 23 | - this.socket.emit("msg", { | 31 | + this.socket.send({ |
| 24 | type: type as string, | 32 | type: type as string, |
| 25 | message: message, | 33 | message: message, |
| 26 | }); | 34 | }); |
| 27 | } | 35 | } |
| 36 | + | ||
| 37 | + public handleRaw(raw: RawMessage): ServerResponse<any> { | ||
| 38 | + const type = raw.type as ServerInboundMessageKey; | ||
| 39 | + const message = raw.message; | ||
| 40 | + | ||
| 41 | + // 유저 정보가 없으므로 로그인은 따로 핸들링 | ||
| 42 | + if (type === "login") { | ||
| 43 | + return this.handleLogin(message); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + // Game > Room > User 순으로 전달 | ||
| 47 | + if (this.user?.room) { | ||
| 48 | + const response = this.user.room.handler.handle(type, this.user, message); | ||
| 49 | + if (response) return response; | ||
| 50 | + } | ||
| 51 | + if (this.user) { | ||
| 52 | + const response = this.user.handler.handle(type, this.user, message); | ||
| 53 | + if (response) return response; | ||
| 54 | + } | ||
| 55 | + return { ok: false }; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + private handleLogin( | ||
| 59 | + message: ServerInboundMessage<"login"> | ||
| 60 | + ): ServerResponse<"login"> { | ||
| 61 | + this.user = new User(message.username, this); | ||
| 62 | + console.log(`User ${message.username} has logged in!`); | ||
| 63 | + | ||
| 64 | + return { ok: true }; | ||
| 65 | + } | ||
| 28 | } | 66 | } | ... | ... |
| 1 | -import { Socket } from "socket.io"; | ||
| 2 | -import { Connection } from "./Connection"; | ||
| 3 | - | ||
| 4 | -export class ConnectionMapper { | ||
| 5 | - private map: Map<Socket, Connection>; | ||
| 6 | - | ||
| 7 | - constructor() { | ||
| 8 | - this.map = new Map<Socket, Connection>(); | ||
| 9 | - } | ||
| 10 | - | ||
| 11 | - public get(socket: Socket): Connection { | ||
| 12 | - var value = this.map.get(socket); | ||
| 13 | - if (value) { | ||
| 14 | - return value; | ||
| 15 | - } | ||
| 16 | - | ||
| 17 | - value = new Connection(socket); | ||
| 18 | - // FIXME: Register connection to the map | ||
| 19 | - return value; | ||
| 20 | - } | ||
| 21 | - | ||
| 22 | - public close(socket: Socket): void { | ||
| 23 | - this.map.delete(socket); | ||
| 24 | - } | ||
| 25 | -} |
server/connection/SocketWrapper.ts
0 → 100644
| 1 | +import { Socket } from "socket.io"; | ||
| 2 | +import { RawMessage, ServerResponse } from "../../common"; | ||
| 3 | + | ||
| 4 | +export interface SocketWrapper { | ||
| 5 | + setHandler: (listener: (raw: RawMessage) => ServerResponse<any>) => void; | ||
| 6 | + send: (raw: RawMessage) => void; | ||
| 7 | +} | ||
| 8 | + | ||
| 9 | +export class SocketIoWrapper implements SocketWrapper { | ||
| 10 | + private socketIo: Socket; | ||
| 11 | + | ||
| 12 | + constructor(socketIo: Socket) { | ||
| 13 | + this.socketIo = socketIo; | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + public setHandler(listener: (raw: RawMessage) => ServerResponse<any>): void { | ||
| 17 | + this.socketIo.on("msg", (raw: RawMessage, callback: Function) => { | ||
| 18 | + callback(listener(raw)); | ||
| 19 | + }); | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + public send(raw: RawMessage) { | ||
| 23 | + this.socketIo.emit("msg", raw); | ||
| 24 | + } | ||
| 25 | +} |
| 1 | -import { Connection } from "../connection/Connection"; | ||
| 2 | import { | 1 | import { |
| 3 | ServerInboundMessage, | 2 | ServerInboundMessage, |
| 4 | ServerInboundMessageKey, | 3 | ServerInboundMessageKey, |
| ... | @@ -23,13 +22,10 @@ export class MessageHandler { | ... | @@ -23,13 +22,10 @@ export class MessageHandler { |
| 23 | public handle( | 22 | public handle( |
| 24 | type: ServerInboundMessageKey, | 23 | type: ServerInboundMessageKey, |
| 25 | user: User, | 24 | user: User, |
| 26 | - message: any, | 25 | + message: any |
| 27 | - callback: Function | 26 | + ): ServerResponse<any> | undefined { |
| 28 | - ): boolean { | ||
| 29 | const handler = this.handlers[type]; | 27 | const handler = this.handlers[type]; |
| 30 | - if (!handler) return false; | 28 | + if (!handler) return undefined; |
| 31 | - const response = handler(user, message); | 29 | + return handler(user, message); |
| 32 | - callback(response); | ||
| 33 | - return true; | ||
| 34 | } | 30 | } |
| 35 | } | 31 | } | ... | ... |
| 1 | -import { Connection } from "../connection/Connection"; | ||
| 2 | -import { | ||
| 3 | - RawMessage, | ||
| 4 | - ServerInboundMessage, | ||
| 5 | - ServerInboundMessageKey, | ||
| 6 | - ServerResponse, | ||
| 7 | -} from "../../common/index"; | ||
| 8 | -import { User } from "../user/User"; | ||
| 9 | - | ||
| 10 | -export class MessageHandlerChain { | ||
| 11 | - connection: Connection; | ||
| 12 | - | ||
| 13 | - constructor(connection: Connection) { | ||
| 14 | - this.connection = connection; | ||
| 15 | - | ||
| 16 | - this.connection.socket.on("msg", (raw: RawMessage, callback: Function) => { | ||
| 17 | - this.handleRaw(connection, raw, callback); | ||
| 18 | - }); | ||
| 19 | - } | ||
| 20 | - | ||
| 21 | - private handleRaw( | ||
| 22 | - connection: Connection, | ||
| 23 | - raw: RawMessage, | ||
| 24 | - callback: Function | ||
| 25 | - ) { | ||
| 26 | - const type = raw.type as ServerInboundMessageKey; | ||
| 27 | - const message = raw.message; | ||
| 28 | - | ||
| 29 | - // 유저 정보가 없으므로 로그인은 따로 핸들링 | ||
| 30 | - if (type === "login") { | ||
| 31 | - this.handleLogin(connection, message, callback); | ||
| 32 | - return; | ||
| 33 | - } | ||
| 34 | - | ||
| 35 | - // Game > Room > User 순으로 전달 | ||
| 36 | - if ( | ||
| 37 | - connection?.user?.room && | ||
| 38 | - connection.user.room.handler.handle( | ||
| 39 | - type, | ||
| 40 | - connection.user, | ||
| 41 | - message, | ||
| 42 | - callback | ||
| 43 | - ) | ||
| 44 | - ) | ||
| 45 | - return; | ||
| 46 | - | ||
| 47 | - if ( | ||
| 48 | - connection?.user && | ||
| 49 | - connection.user.handler.handle(type, connection.user, message, callback) | ||
| 50 | - ) | ||
| 51 | - return; | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - private handleLogin( | ||
| 55 | - connection: Connection, | ||
| 56 | - message: ServerInboundMessage<"login">, | ||
| 57 | - callback: Function | ||
| 58 | - ) { | ||
| 59 | - connection.user = new User(message.username, connection); | ||
| 60 | - console.log(`User ${message.username} has logged in!`); | ||
| 61 | - | ||
| 62 | - callback({ ok: true }); | ||
| 63 | - } | ||
| 64 | -} |
| 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 { User } from "../user/User"; | 3 | import { User } from "../user/User"; |
| 4 | -import { MessageHandlerChain } from "../message/MessageHandlerChain"; | ||
| 5 | import { MessageHandler } from "../message/MessageHandler"; | 4 | import { MessageHandler } from "../message/MessageHandler"; |
| 6 | import { | 5 | import { |
| 7 | ServerInboundMessage, | 6 | ServerInboundMessage, | ... | ... |
| ... | @@ -2,19 +2,12 @@ import { RoomDescription } from "../../common/dataType"; | ... | @@ -2,19 +2,12 @@ import { RoomDescription } from "../../common/dataType"; |
| 2 | import { Room } from "./Room"; | 2 | import { Room } from "./Room"; |
| 3 | 3 | ||
| 4 | export class RoomManager { | 4 | export class RoomManager { |
| 5 | - private static _instance: RoomManager; | ||
| 6 | - | ||
| 7 | private rooms: Map<string, Room>; | 5 | private rooms: Map<string, Room>; |
| 8 | 6 | ||
| 9 | constructor() { | 7 | constructor() { |
| 10 | - RoomManager._instance = this; | ||
| 11 | this.rooms = new Map<string, Room>(); | 8 | this.rooms = new Map<string, Room>(); |
| 12 | } | 9 | } |
| 13 | 10 | ||
| 14 | - public static instance(): RoomManager { | ||
| 15 | - return RoomManager._instance; | ||
| 16 | - } | ||
| 17 | - | ||
| 18 | public create(name: string, maxConnections: number): Room { | 11 | public create(name: string, maxConnections: number): Room { |
| 19 | const room = new Room(name, maxConnections); | 12 | const room = new Room(name, maxConnections); |
| 20 | this.rooms.set(room.uuid, room); | 13 | this.rooms.set(room.uuid, room); | ... | ... |
| ... | @@ -18,10 +18,10 @@ export class User { | ... | @@ -18,10 +18,10 @@ export class User { |
| 18 | this.connection = connection; | 18 | this.connection = connection; |
| 19 | this.handler = new MessageHandler({ | 19 | this.handler = new MessageHandler({ |
| 20 | roomList: (user, message) => { | 20 | roomList: (user, message) => { |
| 21 | - return { ok: true, result: RoomManager.instance().list() }; | 21 | + return { ok: true, result: connection.roomManager.list() }; |
| 22 | }, | 22 | }, |
| 23 | joinRoom: (user, message) => { | 23 | joinRoom: (user, message) => { |
| 24 | - const room = RoomManager.instance().get(message.uuid); | 24 | + const room = connection.roomManager.get(message.uuid); |
| 25 | if (user.room || !room) { | 25 | if (user.room || !room) { |
| 26 | return { ok: false }; | 26 | return { ok: false }; |
| 27 | } | 27 | } | ... | ... |
-
Please register or login to post a comment