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