Showing
5 changed files
with
55 additions
and
0 deletions
| ... | @@ -79,6 +79,9 @@ export class ServerInboundMessageRecordMap { | ... | @@ -79,6 +79,9 @@ export class ServerInboundMessageRecordMap { |
| 79 | x: Number, | 79 | x: Number, |
| 80 | y: Number, | 80 | y: Number, |
| 81 | }); | 81 | }); |
| 82 | + | ||
| 83 | + // 핑을 보냅니다. | ||
| 84 | + ping = Record({}); | ||
| 82 | } | 85 | } |
| 83 | 86 | ||
| 84 | type ServerInboundMessageMap = { | 87 | type ServerInboundMessageMap = { |
| ... | @@ -164,6 +167,9 @@ interface ServerOutboundMessageMap { | ... | @@ -164,6 +167,9 @@ interface ServerOutboundMessageMap { |
| 164 | x: number; | 167 | x: number; |
| 165 | y: number; | 168 | y: number; |
| 166 | }; | 169 | }; |
| 170 | + | ||
| 171 | + // 핑을 보냅니다. | ||
| 172 | + ping: {}; | ||
| 167 | } | 173 | } |
| 168 | 174 | ||
| 169 | export interface RawMessage { | 175 | export interface RawMessage { | ... | ... |
| ... | @@ -26,6 +26,7 @@ export class Connection { | ... | @@ -26,6 +26,7 @@ export class Connection { |
| 26 | this.roomManager = roomManager; | 26 | this.roomManager = roomManager; |
| 27 | socket.setHandler((raw) => this.handleRaw(raw)); | 27 | socket.setHandler((raw) => this.handleRaw(raw)); |
| 28 | socket.setDisconnectHandler(() => this.handleDisconnect()); | 28 | socket.setDisconnectHandler(() => this.handleDisconnect()); |
| 29 | + socket.setPingHandler(() => this.handlePing()); | ||
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | public send<T extends ServerOutboundMessageKey>( | 32 | public send<T extends ServerOutboundMessageKey>( |
| ... | @@ -38,6 +39,10 @@ export class Connection { | ... | @@ -38,6 +39,10 @@ export class Connection { |
| 38 | }); | 39 | }); |
| 39 | } | 40 | } |
| 40 | 41 | ||
| 42 | + public sendPing() { | ||
| 43 | + this.socket.sendPing(); | ||
| 44 | + } | ||
| 45 | + | ||
| 41 | public handleRaw(raw: RawMessage): ServerResponse<any> { | 46 | public handleRaw(raw: RawMessage): ServerResponse<any> { |
| 42 | if (!raw || !raw.message || !raw.type) { | 47 | if (!raw || !raw.message || !raw.type) { |
| 43 | return { ok: false }; | 48 | return { ok: false }; |
| ... | @@ -93,4 +98,10 @@ export class Connection { | ... | @@ -93,4 +98,10 @@ export class Connection { |
| 93 | public handleDisconnect(): void { | 98 | public handleDisconnect(): void { |
| 94 | this.user?.disconnected(); | 99 | this.user?.disconnected(); |
| 95 | } | 100 | } |
| 101 | + | ||
| 102 | + public handlePing(): void { | ||
| 103 | + if (this.user) { | ||
| 104 | + this.user?.room?.pong(this.user); | ||
| 105 | + } | ||
| 106 | + } | ||
| 96 | } | 107 | } | ... | ... |
| ... | @@ -4,7 +4,9 @@ import { RawMessage, ServerResponse } from "../../common"; | ... | @@ -4,7 +4,9 @@ import { RawMessage, ServerResponse } from "../../common"; |
| 4 | export interface SocketWrapper { | 4 | export interface SocketWrapper { |
| 5 | setHandler: (listener: (raw: RawMessage) => ServerResponse<any>) => void; | 5 | setHandler: (listener: (raw: RawMessage) => ServerResponse<any>) => void; |
| 6 | setDisconnectHandler: (listener: () => void) => void; | 6 | setDisconnectHandler: (listener: () => void) => void; |
| 7 | + setPingHandler: (listener: () => void) => void; | ||
| 7 | send: (raw: RawMessage) => void; | 8 | send: (raw: RawMessage) => void; |
| 9 | + sendPing: () => void; | ||
| 8 | } | 10 | } |
| 9 | 11 | ||
| 10 | export class SocketIoWrapper implements SocketWrapper { | 12 | export class SocketIoWrapper implements SocketWrapper { |
| ... | @@ -26,7 +28,17 @@ export class SocketIoWrapper implements SocketWrapper { | ... | @@ -26,7 +28,17 @@ export class SocketIoWrapper implements SocketWrapper { |
| 26 | }); | 28 | }); |
| 27 | } | 29 | } |
| 28 | 30 | ||
| 31 | + public setPingHandler(listener: () => void) { | ||
| 32 | + this.socketIo.on("ping", () => { | ||
| 33 | + listener(); | ||
| 34 | + }); | ||
| 35 | + } | ||
| 36 | + | ||
| 29 | public send(raw: RawMessage) { | 37 | public send(raw: RawMessage) { |
| 30 | this.socketIo.emit("msg", raw); | 38 | this.socketIo.emit("msg", raw); |
| 31 | } | 39 | } |
| 40 | + | ||
| 41 | + public sendPing() { | ||
| 42 | + this.socketIo.emit("ping", {}); | ||
| 43 | + } | ||
| 32 | } | 44 | } | ... | ... |
| ... | @@ -29,6 +29,8 @@ export class Room { | ... | @@ -29,6 +29,8 @@ export class Room { |
| 29 | 29 | ||
| 30 | public handler: MessageHandler; | 30 | public handler: MessageHandler; |
| 31 | 31 | ||
| 32 | + public pingTimeout: NodeJS.Timeout; | ||
| 33 | + | ||
| 32 | constructor( | 34 | constructor( |
| 33 | roomManager: RoomManager, | 35 | roomManager: RoomManager, |
| 34 | name: string, | 36 | name: string, |
| ... | @@ -95,6 +97,8 @@ export class Room { | ... | @@ -95,6 +97,8 @@ export class Room { |
| 95 | if (this.admin) { | 97 | if (this.admin) { |
| 96 | this.connect(this.admin); | 98 | this.connect(this.admin); |
| 97 | } | 99 | } |
| 100 | + | ||
| 101 | + this.pingTimeout = setInterval(() => this.ping(), 1000); | ||
| 98 | } | 102 | } |
| 99 | 103 | ||
| 100 | public connect(user: User): void { | 104 | public connect(user: User): void { |
| ... | @@ -114,6 +118,8 @@ export class Room { | ... | @@ -114,6 +118,8 @@ export class Room { |
| 114 | 118 | ||
| 115 | this.users.push(user); | 119 | this.users.push(user); |
| 116 | user.room = this; | 120 | user.room = this; |
| 121 | + | ||
| 122 | + user.lastPong = Date.now(); | ||
| 117 | } | 123 | } |
| 118 | 124 | ||
| 119 | public disconnect(user: User): void { | 125 | public disconnect(user: User): void { |
| ... | @@ -143,6 +149,23 @@ export class Room { | ... | @@ -143,6 +149,23 @@ export class Room { |
| 143 | } | 149 | } |
| 144 | } | 150 | } |
| 145 | 151 | ||
| 152 | + public ping(): void { | ||
| 153 | + this.users.forEach((u) => { | ||
| 154 | + u.connection.sendPing(); | ||
| 155 | + if (Date.now() - u.lastPong > 2000) { | ||
| 156 | + this.disconnect(u); | ||
| 157 | + } | ||
| 158 | + }); | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + public pong(user: User) { | ||
| 162 | + if (!this.users.includes(user)) { | ||
| 163 | + return { ok: false }; | ||
| 164 | + } | ||
| 165 | + user.lastPong = Date.now(); | ||
| 166 | + return { ok: true }; | ||
| 167 | + } | ||
| 168 | + | ||
| 146 | public setAdmin(user: User) { | 169 | public setAdmin(user: User) { |
| 147 | if (this.users.includes(user)) { | 170 | if (this.users.includes(user)) { |
| 148 | const prevAdmin = this.admin; | 171 | const prevAdmin = this.admin; |
| ... | @@ -272,6 +295,7 @@ export class Room { | ... | @@ -272,6 +295,7 @@ export class Room { |
| 272 | this.users.forEach((u) => this.disconnect(u)); | 295 | this.users.forEach((u) => this.disconnect(u)); |
| 273 | this.closed = true; | 296 | this.closed = true; |
| 274 | this.roomManager.delete(this.uuid); | 297 | this.roomManager.delete(this.uuid); |
| 298 | + clearInterval(this.pingTimeout); | ||
| 275 | } | 299 | } |
| 276 | } | 300 | } |
| 277 | } | 301 | } | ... | ... |
| ... | @@ -15,6 +15,8 @@ export class User { | ... | @@ -15,6 +15,8 @@ export class User { |
| 15 | 15 | ||
| 16 | public handler: MessageHandler; | 16 | public handler: MessageHandler; |
| 17 | 17 | ||
| 18 | + public lastPong: number = 0; // 방에서 마지막으로 핑을 받은 시각 | ||
| 19 | + | ||
| 18 | constructor(nickname: string, connection: Connection) { | 20 | constructor(nickname: string, connection: Connection) { |
| 19 | this.username = uuidv4(); | 21 | this.username = uuidv4(); |
| 20 | this.nickname = nickname; | 22 | this.nickname = nickname; | ... | ... |
-
Please register or login to post a comment