Skip to content

Commit

Permalink
Merge pull request #236 from DongHoonYu96/feature-be-#219#229
Browse files Browse the repository at this point in the history
[BE] feat#219 redis ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๊ตฌํ˜„
  • Loading branch information
DongHoonYu96 authored Nov 21, 2024
2 parents 0881d5b + 30d6b36 commit 57d5438
Show file tree
Hide file tree
Showing 19 changed files with 486 additions and 86 deletions.
48 changes: 48 additions & 0 deletions BE/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions BE/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/platform-socket.io": "^10.4.6",
"@nestjs/schedule": "^4.1.1",
"@nestjs/swagger": "^8.0.5",
"@nestjs/typeorm": "^10.0.2",
"@nestjs/websockets": "^10.4.7",
Expand Down
128 changes: 70 additions & 58 deletions BE/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,70 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GameModule } from './game/game.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { RedisModule } from '@nestjs-modules/ioredis';
import { ConfigModule } from '@nestjs/config';
import { QuizSetModel } from './quiz-set/entities/quiz-set.entity';
import { QuizModel } from './quiz-set/entities/quiz.entity';
import { QuizChoiceModel } from './quiz-set/entities/quiz-choice.entity';
import { UserModel } from './user/entities/user.entity';
import { UserQuizArchiveModel } from './user/entities/user-quiz-archive.entity';
import { InitDBModule } from './InitDB/InitDB.module';
import { UserModule } from './user/user.module';
import { QuizSetModule } from './quiz-set/quiz-set.module';
import { WaitingRoomModule } from './waiting-room/waiting-room.module';
import { TimeController } from './time/time.controller';
import { TimeModule } from './time/time.module';
import { AuthModule } from './auth/auth.module';

@Module({
imports: [
ConfigModule.forRoot({
envFilePath: '../.env',
isGlobal: true
}),
GameModule,
TypeOrmModule.forRoot({
type: 'mysql',
host: process.env.DB_HOST || 'localhost',
port: +process.env.DB_PORT || 3306,
username: process.env.DB_USER || 'root',
password: process.env.DB_PASSWD || 'test',
database: process.env.DB_NAME || 'test_db',
entities: [QuizSetModel, QuizModel, QuizChoiceModel, UserModel, UserQuizArchiveModel],
synchronize: process.env.DEV ? true : false, // ๊ฐœ๋ฐœ ๋ชจ๋“œ์—์„œ๋งŒ ํ™œ์„ฑํ™”
logging: true, // ๋ชจ๋“  ์ฟผ๋ฆฌ ๋กœ๊น…
logger: 'advanced-console'
// extra: {
// // ๊ธ€๋กœ๋ฒŒ batch size ์„ค์ •
// maxBatchSize: 100
// }
}),
RedisModule.forRoot({
type: 'single',
url: process.env.REDIS_URL || 'redis://localhost:6379'
}),
QuizSetModule,
UserModule,
InitDBModule,
WaitingRoomModule,
TimeModule
AuthModule
],
controllers: [AppController, TimeController],
providers: [AppService]
})
export class AppModule {}
import { ClassSerializerInterceptor, Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GameModule } from './game/game.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { RedisModule } from '@nestjs-modules/ioredis';
import { ConfigModule } from '@nestjs/config';
import { QuizSetModel } from './quiz-set/entities/quiz-set.entity';
import { QuizModel } from './quiz-set/entities/quiz.entity';
import { QuizChoiceModel } from './quiz-set/entities/quiz-choice.entity';
import { UserModel } from './user/entities/user.entity';
import { UserQuizArchiveModel } from './user/entities/user-quiz-archive.entity';
import { InitDBModule } from './InitDB/InitDB.module';
import { UserModule } from './user/user.module';
import { QuizSetModule } from './quiz-set/quiz-set.module';
import { WaitingRoomModule } from './waiting-room/waiting-room.module';
import { TimeController } from './time/time.controller';
import { TimeModule } from './time/time.module';
import { AuthModule } from './auth/auth.module';
import { ScheduleModule } from '@nestjs/schedule';
import { GameRedisMemoryService } from './game/redis/game-redis-memory.service';
import { APP_INTERCEPTOR } from '@nestjs/core';

@Module({
imports: [
ConfigModule.forRoot({
envFilePath: '../.env',
isGlobal: true
}),
GameModule,
// ์Šค์ผ€์ค„๋Ÿฌ ๋ชจ๋“ˆ ์ถ”๊ฐ€ (Redis ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์„œ๋น„์Šค์˜ @Cron ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์‚ฌ์šฉ์„ ์œ„ํ•ด)
ScheduleModule.forRoot(),
TypeOrmModule.forRoot({
type: 'mysql',
host: process.env.DB_HOST || 'localhost',
port: +process.env.DB_PORT || 3306,
username: process.env.DB_USER || 'root',
password: process.env.DB_PASSWD || 'test',
database: process.env.DB_NAME || 'test_db',
entities: [QuizSetModel, QuizModel, QuizChoiceModel, UserModel, UserQuizArchiveModel],
synchronize: process.env.DEV ? true : false, // ๊ฐœ๋ฐœ ๋ชจ๋“œ์—์„œ๋งŒ ํ™œ์„ฑํ™”
logging: true, // ๋ชจ๋“  ์ฟผ๋ฆฌ ๋กœ๊น…
logger: 'advanced-console'
// extra: {
// // ๊ธ€๋กœ๋ฒŒ batch size ์„ค์ •
// maxBatchSize: 100
// }
}),
RedisModule.forRoot({
type: 'single',
url: process.env.REDIS_URL || 'redis://localhost:6379'
}),
QuizSetModule,
UserModule,
InitDBModule,
WaitingRoomModule,
TimeModule,
AuthModule
],
controllers: [AppController, TimeController],
providers: [
AppService,
GameRedisMemoryService,
{
provide: APP_INTERCEPTOR,
useClass: ClassSerializerInterceptor
}
]
})
export class AppModule {}
9 changes: 6 additions & 3 deletions BE/src/game/game.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
WebSocketServer
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { Logger, UseFilters, UsePipes } from '@nestjs/common';
import { Logger, UseFilters, UseInterceptors, UsePipes } from '@nestjs/common';
import { WsExceptionFilter } from '../common/filters/ws-exception.filter';
import SocketEvents from '../common/constants/socket-events';
import { CreateGameDto } from './dto/create-game.dto';
Expand All @@ -20,7 +20,9 @@ import { UpdateRoomOptionDto } from './dto/update-room-option.dto';
import { UpdateRoomQuizsetDto } from './dto/update-room-quizset.dto';
import { GameChatService } from './service/game.chat.service';
import { GameRoomService } from './service/game.room.service';
import { GameActivityInterceptor } from './interceptor/gameActivity.interceptor';

@UseInterceptors(GameActivityInterceptor)
@UseFilters(new WsExceptionFilter())
@WebSocketGateway({
cors: {
Expand Down Expand Up @@ -120,9 +122,10 @@ export class GameGateway {
this.logger.verbose(`ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋˜์—ˆ์–ด์š”!: ${client.id}`);
}

handleDisconnect(client: Socket) {
async handleDisconnect(client: Socket) {
this.logger.verbose(`ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ ํ•ด์ œ๋˜์—ˆ์–ด์š”!: ${client.id}`);

this.gameService.disconnect(client.id);
await this.gameService.disconnect(client.id);
await this.gameRoomService.handlePlayerExit(client.id);
}
}
14 changes: 8 additions & 6 deletions BE/src/game/game.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { GameRoomService } from './service/game.room.service';
import { QuizCacheService } from './service/quiz.cache.service';
import { QuizSetModule } from '../quiz-set/quiz-set.module';
import { QuizSetService } from '../quiz-set/service/quiz-set.service';
import { ScoringSubscriber } from '../common/redis/subscribers/scoring.subscriber';
import { TimerSubscriber } from '../common/redis/subscribers/timer.subscriber';
import { RoomSubscriber } from '../common/redis/subscribers/room.subscriber';
import { PlayerSubscriber } from '../common/redis/subscribers/player.subscriber';
import { RedisSubscriberService } from '../common/redis/redis-subscriber.service';
import { RedisSubscriberService } from './redis/redis-subscriber.service';
import { ScoringSubscriber } from './redis/subscribers/scoring.subscriber';
import { TimerSubscriber } from './redis/subscribers/timer.subscriber';
import { RoomSubscriber } from './redis/subscribers/room.subscriber';
import { PlayerSubscriber } from './redis/subscribers/player.subscriber';
import { RoomCleanupSubscriber } from './redis/subscribers/room.cleanup.subscriber';

@Module({
imports: [RedisModule, QuizSetModule],
Expand All @@ -28,7 +29,8 @@ import { RedisSubscriberService } from '../common/redis/redis-subscriber.service
ScoringSubscriber,
TimerSubscriber,
RoomSubscriber,
PlayerSubscriber
PlayerSubscriber,
RoomCleanupSubscriber
],
exports: [GameService]
})
Expand Down
28 changes: 28 additions & 0 deletions BE/src/game/interceptor/gameActivity.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// ํ™œ๋™ ์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ„๋ฆฌ
import { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common';
import { of } from 'rxjs';
import { GameRoomService } from '../service/game.room.service';

@Injectable()
export class GameActivityInterceptor implements NestInterceptor {
private readonly logger = new Logger(GameActivityInterceptor.name);

constructor(private readonly gameRoomService: GameRoomService) {}

async intercept(context: ExecutionContext, next: CallHandler) {
// ํ•ต์‹ฌ ๋กœ์ง ์‹คํ–‰ ์ „
const before = Date.now();

// ํ•ต์‹ฌ ๋กœ์ง ์‹คํ–‰
const result = await next.handle().toPromise();

// ํ™œ๋™ ์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ (๋ถ€๊ฐ€ ๊ธฐ๋Šฅ)
const data = context.switchToWs().getData();
if (data.gameId) {
await this.gameRoomService.updateRoomActivity(data.gameId);
this.logger.debug(`Activity updated for room ${data.gameId} after ${Date.now() - before}ms`);
}

return of(result);
}
}
Loading

0 comments on commit 57d5438

Please sign in to comment.