From 99d84b8d8cf1bfecc1e1c57d4b724a4afc86e8dc Mon Sep 17 00:00:00 2001 From: student079 Date: Thu, 28 Nov 2024 12:47:06 +0900 Subject: [PATCH] =?UTF-8?q?chore:=20sse=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/modules/rooms/rooms.controller.ts | 104 ++++++------------ .../src/modules/rooms/rooms.gateway.ts | 48 ++++++-- be/gameServer/src/redis/redis.service.ts | 25 +---- 3 files changed, 76 insertions(+), 101 deletions(-) diff --git a/be/gameServer/src/modules/rooms/rooms.controller.ts b/be/gameServer/src/modules/rooms/rooms.controller.ts index 25a5413..5a5eb40 100644 --- a/be/gameServer/src/modules/rooms/rooms.controller.ts +++ b/be/gameServer/src/modules/rooms/rooms.controller.ts @@ -8,6 +8,7 @@ import { NotFoundException, Query, Delete, + ParseIntPipe, } from '@nestjs/common'; import { RedisService } from '../../redis/redis.service'; import { RoomDataDto } from './dto/room-data.dto'; @@ -52,93 +53,50 @@ export class RoomController { description: '현재 페이지의 게임 방 목록이 성공적으로 반환됩니다.', type: [RoomDataDto], }) - getRoomUpdates(@Query('page') page: number = 0): Observable { + getRoomUpdates( + @Query('page', ParseIntPipe) page: number = 0, + ): Observable { const start = page * RoomsConstant.ROOMS_LIMIT; const end = start + RoomsConstant.ROOMS_LIMIT - 1; return this.roomUpdateSubject.pipe( concatMap(async (event: MessageEvent) => { - const messageString = event.data as string; - const message = JSON.parse(messageString); - const { type, key, nextPage, deletedPage } = message; - const updatedRoomKey = key ? key.slice(5) : null; + const totalRooms = await this.redisService.llen('roomsList'); + const totalPages = Math.ceil(totalRooms / RoomsConstant.ROOMS_LIMIT); const roomList = await this.redisService.lrange( 'roomsList', start, end, ); - if (type === 'CREATE') { - if (roomList.includes(updatedRoomKey)) { - const rooms = await Promise.all( - roomList.map(async (roomKey) => { - const roomData = await this.redisService.hgetAll( - `room:${roomKey}`, - ); - return roomData; - }), - ); - return { - data: rooms, - } as MessageEvent; - } else { - return null; - } - } else if (type === 'DELETE') { - if (page != deletedPage) { - return null; - } else { - const rooms = await Promise.all( - roomList.map(async (roomKey) => { - const roomData = await this.redisService.hgetAll( - `room:${roomKey}`, - ); - return roomData; - }), - ); - if (rooms.length === RoomsConstant.ROOMS_LIMIT) { - const nextPageEvent = { - data: JSON.stringify({ - type: 'UPDATE', - nextPage: Number(page) + 1, - }), - }; + const messageString = event.data as string; + const message = JSON.parse(messageString); + const { updatePage } = message; - this.roomUpdateSubject.next(nextPageEvent); - } - return { - data: rooms, - } as MessageEvent; - } - } else if (type === 'UPDATE') { - if (page != nextPage) { - return null; - } - const rooms = await Promise.all( - roomList.map(async (roomKey) => { - const roomData = await this.redisService.hgetAll( - `room:${roomKey}`, - ); - return roomData; - }), - ); + if (updatePage !== undefined && updatePage != page) { + return null; + } - if (rooms.length === RoomsConstant.ROOMS_LIMIT) { - const nextPageEvent = { - data: JSON.stringify({ - type: 'UPDATE', - nextPage: Number(page) + 1, - }), - }; - this.logger.log( - `SSE 업데이트 이벤트 현재 page: ${Number(page)} 다음 page: ${Number(page) + 1}`, + const rooms = await Promise.all( + roomList.map(async (roomKey) => { + const roomData = await this.redisService.hgetAll( + `room:${roomKey}`, ); - this.roomUpdateSubject.next(nextPageEvent); - } - return { - data: rooms, - } as MessageEvent; - } + return roomData; + }), + ); + return { + data: { + rooms: rooms, + pagination: { + currentPage: Number(page), + totalPages, + totalItems: totalRooms, + hasNextPage: page < totalPages - 1, + hasPreviousPage: page > 0, + }, + }, + } as MessageEvent; }), filter((event: MessageEvent) => event !== null), ); diff --git a/be/gameServer/src/modules/rooms/rooms.gateway.ts b/be/gameServer/src/modules/rooms/rooms.gateway.ts index d51afbe..521c826 100644 --- a/be/gameServer/src/modules/rooms/rooms.gateway.ts +++ b/be/gameServer/src/modules/rooms/rooms.gateway.ts @@ -64,11 +64,13 @@ export class RoomsGateway implements OnGatewayDisconnect { }; await this.redisService.rpush(RedisKeys.ROOMS_LIST, roomId); + await this.redisService.hmset( `room:${roomId}`, convertRoomDataToHash(roomData), RedisKeys.ROOMS_UPDATE_CHANNEL, ); + await this.redisService.rpush( `${RedisKeys.ROOM_NAME_TO_ID_HASH}:${roomName}`, roomId, @@ -123,12 +125,22 @@ export class RoomsGateway implements OnGatewayDisconnect { } roomData.players.push({ playerNickname, isReady: false, isMuted: false }); + + const totalRoomIdList = await this.redisService.lrange( + `${RedisKeys.ROOMS_LIST}`, + 0, + -1, + ); + const index = totalRoomIdList.indexOf(roomId); await this.redisService.hmset( `room:${roomId}`, { players: JSON.stringify(roomData.players), }, RedisKeys.ROOMS_UPDATE_CHANNEL, + ...(index === -1 + ? [] + : [Math.floor(index / RoomsConstant.ROOMS_LIMIT)]), ); client.join(roomId); @@ -162,6 +174,12 @@ export class RoomsGateway implements OnGatewayDisconnect { // 이 상태에서 다른 사용자가 방에 들어온다면? if (roomData.hostNickname === playerNickname) { + const totalRoomIdList = await this.redisService.lrange( + `${RedisKeys.ROOMS_LIST}`, + 0, + -1, + ); + const index = totalRoomIdList.indexOf(roomId); if (roomData.players.length > 0) { changeRoomHost(roomData); await this.redisService.hmset( @@ -171,6 +189,9 @@ export class RoomsGateway implements OnGatewayDisconnect { hostNickname: roomData.hostNickname, }, RedisKeys.ROOMS_UPDATE_CHANNEL, + ...(index === -1 + ? [] + : [Math.floor(index / RoomsConstant.ROOMS_LIMIT)]), ); this.logger.log(`host ${playerNickname} leave room`); @@ -192,28 +213,28 @@ export class RoomsGateway implements OnGatewayDisconnect { if (roomNameList.length === 0) { await this.redisService.zrem('roomNames', roomData.roomName); } - const totalRoomIdList = await this.redisService.lrange( - `${RedisKeys.ROOMS_LIST}`, - 0, - -1, - ); - const index = totalRoomIdList.indexOf(roomId); await this.redisService.lrem(RedisKeys.ROOMS_LIST, roomId); await this.redisService.delete( `room:${roomId}`, RedisKeys.ROOMS_UPDATE_CHANNEL, - ...(index === -1 - ? [] - : [Math.floor(index / RoomsConstant.ROOMS_LIMIT)]), ); } } else { + const totalRoomIdList = await this.redisService.lrange( + `${RedisKeys.ROOMS_LIST}`, + 0, + -1, + ); + const index = totalRoomIdList.indexOf(roomId); await this.redisService.hmset( `room:${roomId}`, { players: JSON.stringify(roomData.players), }, RedisKeys.ROOMS_UPDATE_CHANNEL, + ...(index === -1 + ? [] + : [Math.floor(index / RoomsConstant.ROOMS_LIMIT)]), ); this.logger.log(`host ${playerNickname} leave room`); this.server.to(roomId).emit('updateUsers', roomData.players); @@ -334,12 +355,21 @@ export class RoomsGateway implements OnGatewayDisconnect { if (targetSocket) { roomData.players.splice(playerIndex, 1); + const totalRoomIdList = await this.redisService.lrange( + `${RedisKeys.ROOMS_LIST}`, + 0, + -1, + ); + const index = totalRoomIdList.indexOf(roomId); await this.redisService.hmset( `room:${roomId}`, { players: JSON.stringify(roomData.players), }, RedisKeys.ROOMS_UPDATE_CHANNEL, + ...(index === -1 + ? [] + : [Math.floor(index / RoomsConstant.ROOMS_LIMIT)]), ); this.server.to(roomId).emit('kicked', playerNickname); diff --git a/be/gameServer/src/redis/redis.service.ts b/be/gameServer/src/redis/redis.service.ts index 0e183dc..d771f84 100644 --- a/be/gameServer/src/redis/redis.service.ts +++ b/be/gameServer/src/redis/redis.service.ts @@ -69,19 +69,17 @@ export class RedisService implements OnModuleDestroy { key: string, fields: Record, channel?: string, - ttlInSeconds?: number, + updatePage?: number, ): Promise { const fieldsArray = Object.entries(fields).flat(); await this.redisClient.hmset(key, ...fieldsArray); - if (ttlInSeconds) { - await this.redisClient.expire(key, ttlInSeconds); - } - if (channel) { await this.publishToChannel( channel, - JSON.stringify({ type: 'CREATE', key }), + JSON.stringify({ + ...(updatePage !== undefined ? { updatePage } : {}), + }), ); } } @@ -115,21 +113,10 @@ export class RedisService implements OnModuleDestroy { return value ? JSON.parse(value) : null; } - async delete( - key: string, - channel?: string, - deletedPage?: number, - ): Promise { + async delete(key: string, channel?: string): Promise { await this.redisClient.del(key); if (channel) { - await this.publishToChannel( - channel, - JSON.stringify({ - type: 'DELETE', - key, - ...(deletedPage !== undefined ? { deletedPage } : {}), - }), - ); + await this.publishToChannel(channel, JSON.stringify({})); } }