Skip to content

Commit 705aa7e

Browse files
committed
Release v1.0.0
1 parent c4a16b5 commit 705aa7e

File tree

6 files changed

+260
-90
lines changed

6 files changed

+260
-90
lines changed

src/config/swagger-config.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ export default () => ({
66
});
77

88
const API_VERSION = 'api/v1';
9-
// USER CONFIG
109
const SWAGGER_OPTIONS = new DocumentBuilder()
1110
.setTitle('모도코 API')
1211
.setDescription('Documentation for Modoco API')
13-
.setVersion('0.0.2')
12+
.setVersion('1.0.0')
1413
.setContact('Juhyeong Ko', 'https://modocode.com', '[email protected]')
1514
.addTag('users', 'Users API')
1615
.addTag('rooms', 'Rooms API')

src/gateways/room.gateway.service.ts

Lines changed: 116 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,6 @@ export class RoomGatewayService {
6464
this.logger.log('[Init] Initialized RoomGateway');
6565
}
6666

67-
/**
68-
* set server instance
69-
* @param {Server} server server instance
70-
*/
71-
setServer(server: Server) {
72-
this.server = server;
73-
}
74-
7567
/**
7668
* [COMMON]
7769
* onConnection - on connection
@@ -81,27 +73,27 @@ export class RoomGatewayService {
8173
*/
8274
async onConnection(client: Socket) {
8375
try {
84-
// pull authentification data
76+
// 1. pull authentification data
8577
const { sub } = await this.authService.verifyToken(
8678
client.handshake.query.token as string,
8779
);
8880
const uid = sub as number;
8981

90-
// attach user data
82+
// 2. attach user data
9183
client.data.uid = uid;
9284
client.data.nickname =
9385
await this.usersDatabaseHelper.getUserNicknameByUid(uid);
9486

95-
// Enable socket session
87+
// 3. enable socket session (if not exist, create one)
9688
await this.createRedisSession(uid, client.data.nickname);
9789

98-
// join uid room
90+
// 4. join uid room for direct message
9991
client.join(uid.toString());
10092

101-
// fetch message
93+
// 5. fetch message history
94+
// should be moved to a separate event
10295
const messages = await this.redisMessageStore.findMessagesForUser(uid);
10396
const messageDict = new Map<number, any[]>();
104-
10597
messages.forEach((message) => {
10698
const { from, to } = message;
10799
const key = uid === from ? to : from;
@@ -111,12 +103,12 @@ export class RoomGatewayService {
111103
messageDict.get(key).push(message);
112104
});
113105

114-
// find all friends of the user
106+
// 7. find all friends of the user
115107
const friendlist = await this.friendDatabaseHelper.getAcceptedFriendships(
116108
uid,
117109
);
118110

119-
// send friends status and messages they have sent
111+
// 8. send friends status and messages they have sent
120112
const friendStatusList = [];
121113
for (const friend of friendlist) {
122114
const friendData =
@@ -138,62 +130,39 @@ export class RoomGatewayService {
138130
}
139131
client.emit('friend:sync-all', friendStatusList);
140132

141-
// notify existing user - that new user is connected
133+
// 9. notify existing user - that new user is connected
142134
// TODO: notify only to the friends of the user who is connected
143135
client.broadcast.emit('friend:connection', {
144136
uid,
145137
nickname: client.data.nickname,
146138
connection: ConnectionType.ONLINE,
147139
});
148140

149-
// log the new connection
141+
// 10. log the new connection
150142
this.logger.log(`[Connection] Client uid: ${uid}, sid: ${client.id}`);
151143
} catch (error) {
152144
this.logger.error(error);
153145
}
154146

155-
// attach handler to disconnecting event
147+
// 11. attach handler to disconnecting event
156148
client.on('disconnecting', () => this.onDisconnecting(client));
157149
}
158150

159-
private async createRedisSession(uid: number, nickname?: string) {
160-
const session = await this.redisSessionStore.findSession(uid);
161-
162-
// no session found, create a new one
163-
if (!session) {
164-
return this.redisSessionStore.saveSession(uid, {
165-
uid,
166-
nickname,
167-
connection: ConnectionType.ONLINE,
168-
});
169-
}
170-
171-
// session found, update the session
172-
return this.redisSessionStore.saveSession(uid, {
173-
connection: ConnectionType.ONLINE,
174-
});
175-
}
176-
177-
private async disableRedisSession(uid: number) {
178-
return this.redisSessionStore.saveSession(uid, {
179-
connection: ConnectionType.OFFLINE,
180-
});
181-
}
182-
183151
/**
184152
* onDisconnect - on disconnect
185153
* emit a user left event to all users in the room
186154
* @param {Socket} client client socket
187155
*/
188156
onDisconnect(client: Socket) {
157+
// 1. log the disconnection
189158
this.logger.log(
190159
`[Disconnect] Client uid: ${client.data.uid},sid: ${client.id}`,
191160
);
192161

193-
// !TODO Disable socket session
162+
// 2. disable socket session
194163
this.disableRedisSession(client.data.uid);
195164

196-
// notify existing user - that new user is disconnected
165+
// 3. notify existing user to update their friend list
197166
client.broadcast.emit('friend:disconnection', {
198167
uid: client.data.uid,
199168
nickname: client.data.nickname,
@@ -230,8 +199,6 @@ export class RoomGatewayService {
230199

231200
// 6. log the event
232201
this.logger.log(`[JoinRoom #${room}] uid: ${uid}, sid: ${client.id}`);
233-
234-
// 7. Create Session
235202
} catch (error) {
236203
if (error instanceof WsException) {
237204
if (error.message === EVENT.ALREADY_JOINED) {
@@ -390,7 +357,7 @@ export class RoomGatewayService {
390357
throw new WsException(KICK_USER_EXCEPTION.IS_MODERATOR);
391358
}
392359

393-
// return user to kick
360+
// 8. return user to kick
394361
return { userToKick, userToKickSocket };
395362
}
396363

@@ -405,27 +372,29 @@ export class RoomGatewayService {
405372
async onLeaveRoom(client: Socket, payload: LeaveRoomPayload) {
406373
const room = payload.room;
407374

375+
// 1. remove user from room
408376
client.leave(room);
409377

378+
// 2. decrement room current count
410379
const currentRoomMembersCount = await getExistingRoomMembersCount(
411380
this.server,
412381
room,
413382
);
414-
// decrement room current count
415383
await this.roomsDatabaseHelper.updateRoomInfoByDelta(
416384
parseInt(room, 10),
417385
currentRoomMembersCount,
418386
0,
419387
);
420388

389+
// 3. notify to user who is leaving & other users in the room
421390
client.emit(EVENT.LEFT_ROOM, {
422391
sid: client.id,
423392
});
424-
425393
client.to(room).emit(EVENT.LEFT_ROOM, {
426394
sid: client.id,
427395
});
428396

397+
// 4. log the event
429398
this.logger.log(
430399
`[LeaveRoom #${room}] Client uid: ${
431400
client.data.uid ? client.data.uid : '?'
@@ -447,8 +416,8 @@ export class RoomGatewayService {
447416
}
448417

449418
async onDirectMessage(client: Socket, messagePayload: DirectMessagePayload) {
419+
// 1. send direct message to target user & sender(`from`)
450420
const from = getSocketUser(client).uid;
451-
452421
this.server
453422
.to(messagePayload.to.toString())
454423
.to(from.toString())
@@ -457,6 +426,7 @@ export class RoomGatewayService {
457426
...messagePayload,
458427
});
459428

429+
// 2. save direct message to database
460430
await this.redisMessageStore.saveMessage({ from, ...messagePayload });
461431
}
462432

@@ -500,19 +470,9 @@ export class RoomGatewayService {
500470
});
501471
}
502472

503-
/**
504-
* record the duration of a user in a room
505-
* @param {Socket} client client socket
506-
* @param {RecordPayload} payload Record event Payload
507-
*/
508-
async onRecordTime(client: Socket, payload: RecordPayload) {
509-
const user = getSocketUser(client);
510-
await this.recordsService.recordTime(user, payload);
511-
}
512-
513473
/**
514474
* on media(video or audio) state change
515-
* @param {EVENT} mediaType
475+
* @param {EVENT} mediaType media type
516476
* @param {Socket} client client socket
517477
* @param {RecordPayload} payload Media state change event Payload
518478
*/
@@ -534,54 +494,123 @@ export class RoomGatewayService {
534494
}
535495
}
536496

537-
// before leaving the room, notify all users in the room that the user has left
538-
private onDisconnecting(client) {
497+
/**
498+
* record the duration of a user in a room
499+
* @warning this function has many bugs
500+
* @param {Socket} client client socket
501+
* @param {RecordPayload} payload Record event Payload
502+
*/
503+
async onRecordTime(client: Socket, payload: RecordPayload) {
504+
const user = getSocketUser(client);
505+
await this.recordsService.recordTime(user, payload);
506+
}
507+
508+
/**
509+
* set server instance
510+
* @param {Server} server server instance
511+
* @private
512+
*/
513+
private setServer(server: Server) {
514+
this.server = server;
515+
}
516+
517+
/**
518+
* called when a user disconnects.
519+
* before leaving the room, notify all users in the room that the user has left
520+
* @param {Socket} client client socket which is about to leave the room
521+
* @private
522+
*/
523+
private onDisconnecting(client: Socket) {
524+
// 1. get all rooms the user is in
539525
const roomsToLeave: Set<string> = this.server.adapter['sids'].get(
540526
client.id,
541527
);
542-
if (roomsToLeave) {
543-
// rooms excluding the room the user's id room
544-
const rooms = [...roomsToLeave].filter(
545-
(room) => room !== client.id && room !== client.data.uid.toString(),
546-
);
528+
if (!roomsToLeave) {
529+
return;
530+
}
547531

548-
rooms.forEach(async (room) => {
549-
// get all users who in currently in the room
550-
const currentRoomMembers = await this.server.in(room).fetchSockets();
551-
// decrement room current count
552-
// minus one because current user, who is leaving, is still in the room
553-
await this.roomsDatabaseHelper.updateRoomInfoByDelta(
554-
parseInt(room, 10),
555-
currentRoomMembers.length,
556-
-1,
557-
);
532+
// 2. get rooms excluding the room, which the user's id is the same as the room id
533+
const rooms = [...roomsToLeave].filter(
534+
(room) => room !== client.id && room !== client.data.uid.toString(),
535+
);
558536

559-
// emit a `leftRoom` event to all users in the room except the sender
560-
client.to(room).emit(EVENT.LEFT_ROOM, {
561-
sid: client.id,
562-
});
537+
// 3. notify to all user that this user is leaving the room
538+
rooms.forEach(async (room) => {
539+
// 3-1. get all users who in currently in the room
540+
const currentRoomMembers = await this.server.in(room).fetchSockets();
541+
// 3-2. decrement room current count
542+
// NOTE: minus one because current user, who is leaving, is still in the room
543+
await this.roomsDatabaseHelper.updateRoomInfoByDelta(
544+
parseInt(room, 10),
545+
currentRoomMembers.length,
546+
-1,
547+
);
548+
549+
// 3-3. emit a `leftRoom` event to all users in the room except the sender
550+
client.to(room).emit(EVENT.LEFT_ROOM, {
551+
sid: client.id,
563552
});
564-
}
553+
});
565554
}
566555

556+
/**
557+
* validate join room payload
558+
* @param {Socket} client client socket
559+
* @param {string} room room id
560+
*/
567561
private async validateJoinRoomPayload(client: Socket, room: string) {
568-
// check if client is already in the room
562+
// 1. check if client is already in the room
569563
const hasJoined = client.rooms.has(room);
570564
if (hasJoined) {
571565
throw new WsException(EVENT.ALREADY_JOINED);
572566
}
573567

574-
// check if room exceeds max capacity
568+
// 2. check if room exceeds max capacity
575569
const roomCapacity = await this.roomsDatabaseHelper.getRoomCapacity(
576570
parseInt(room),
577571
);
578572
let roomCurrentCount = 0;
579573
if (this.server.adapter['rooms'].get(room) !== undefined) {
580574
roomCurrentCount = this.server.adapter['rooms'].get(room).size;
581575
}
582-
583576
if (roomCurrentCount >= roomCapacity) {
584577
throw new WsException(EVENT.ROOM_FULL);
585578
}
586579
}
580+
581+
/**
582+
* [REDIS]
583+
* create a user session in the redis store
584+
* @param {number} uid user id
585+
* @param {string} nickname nickname
586+
*/
587+
private async createRedisSession(uid: number, nickname?: string) {
588+
// 1. find user in the redis store
589+
const session = await this.redisSessionStore.findSession(uid);
590+
591+
// 2. if no session found, create a new one
592+
if (!session) {
593+
return this.redisSessionStore.saveSession(uid, {
594+
uid,
595+
nickname,
596+
connection: ConnectionType.ONLINE,
597+
});
598+
}
599+
600+
// 3. session found, update the session
601+
return this.redisSessionStore.saveSession(uid, {
602+
connection: ConnectionType.ONLINE,
603+
});
604+
}
605+
606+
/**
607+
* [REDIS]
608+
* disable a user session in the redis store
609+
* @param {number} uid user id
610+
*/
611+
private async disableRedisSession(uid: number) {
612+
return this.redisSessionStore.saveSession(uid, {
613+
connection: ConnectionType.OFFLINE,
614+
});
615+
}
587616
}

0 commit comments

Comments
 (0)