-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: Improve code structure with error handling (#87)
* refactor: Separate Gateway, Service, and Repository layers * feat: Add WebSocket error handling * fix: Remove test codes
- Loading branch information
Showing
15 changed files
with
334 additions
and
155 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { ChatGateway } from './chat.gateway'; | ||
import { RedisModule } from 'src/redis/redis.module'; | ||
import { ChatService } from './chat.service'; | ||
import { ChatRepository } from './chat.repository'; | ||
|
||
@Module({ | ||
imports: [RedisModule], | ||
providers: [ChatGateway] | ||
providers: [ChatGateway, ChatService, ChatRepository] | ||
}) | ||
export class ChatModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { Injectable } from "@nestjs/common"; | ||
import { RedisService } from "src/redis/redis.service"; | ||
import { Player } from "src/common/types/game.types"; | ||
|
||
@Injectable() | ||
export class ChatRepository { | ||
constructor(private readonly redisService: RedisService) {} | ||
|
||
async getPlayer(roomId: string, playerId: string) { | ||
const player = await this.redisService.hgetall(`room:${roomId}:players:${playerId}`); | ||
if (!player || Object.keys(player).length === 0) return null; | ||
|
||
return { | ||
...player, | ||
role: player.role === '' ? null : player.role, | ||
profileImage: player.userImg === '' ? null : player.userImg, | ||
score: parseInt(player.score, 10) || 0, | ||
} as Player; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Test, TestingModule } from '@nestjs/testing'; | ||
import { ChatService } from './chat.service'; | ||
|
||
describe('ChatService', () => { | ||
let service: ChatService; | ||
|
||
beforeEach(async () => { | ||
const module: TestingModule = await Test.createTestingModule({ | ||
providers: [ChatService], | ||
}).compile(); | ||
|
||
service = module.get<ChatService>(ChatService); | ||
}); | ||
|
||
it('should be defined', () => { | ||
expect(service).toBeDefined(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
import { ChatRepository } from './chat.repository'; | ||
import { BadRequestException, PlayerNotFoundException } from 'src/exceptions/game.exception'; | ||
|
||
@Injectable() | ||
export class ChatService { | ||
constructor(private readonly chatRepository: ChatRepository) {} | ||
|
||
async sendMessage(roomId: string, playerId: string, message: string) { | ||
if (!message?.trim()) { | ||
throw new BadRequestException('Message cannot be empty'); | ||
} | ||
|
||
const player = await this.chatRepository.getPlayer(roomId, playerId); | ||
if (!player) throw new PlayerNotFoundException(); | ||
|
||
return { | ||
playerId, | ||
nickname: player.nickname, | ||
message, | ||
createdAt: new Date(), | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
export enum PlayerStatus { | ||
NOT_READY = 'NOT_READY', | ||
READY = 'READY', | ||
PLAYING = 'PLAYING', | ||
} | ||
|
||
export enum PlayerRole { | ||
PAINTER = 'PAINTER', | ||
DEVIL = 'DEVIL', | ||
GUESSER = 'GUESSER', | ||
} | ||
|
||
export enum RoomStatus { | ||
WAITING = 'WAITING', | ||
IN_GAME = 'IN_GAME', | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
export enum SocketErrorCode { | ||
BAD_REQUEST = 4000, | ||
UNAUTHORIZED = 4001, | ||
FORBIDDEN = 4003, | ||
NOT_FOUND = 4004, | ||
VALIDATION_ERROR = 4400, | ||
RATE_LIMIT = 4429, | ||
|
||
INTERNAL_ERROR = 5000, | ||
NOT_IMPLEMENTED = 5001, | ||
SERVICE_UNAVAILABLE = 5003, | ||
|
||
GAME_NOT_STARTED = 6001, | ||
GAME_ALREADY_STARTED = 6002, | ||
INVALID_TURN = 6003, | ||
ROOM_FULL = 6004, | ||
ROOM_NOT_FOUND = 6005, | ||
PLAYER_NOT_FOUND = 6006, | ||
INSUFFICIENT_PLAYERS = 6007, | ||
|
||
CONNECTION_ERROR = 7000, | ||
CONNECTION_TIMEOUT = 7001, | ||
CONNECTION_CLOSED = 7002, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { SocketErrorCode } from "../common/enums/socket.error-code.enum"; | ||
|
||
export class GameException extends Error { | ||
constructor( | ||
public readonly code: SocketErrorCode, | ||
message: string, | ||
) { | ||
super(message); | ||
} | ||
} | ||
|
||
export class RoomFullException extends GameException { | ||
constructor(message: string = 'Room is full') { | ||
super(SocketErrorCode.ROOM_FULL, message); | ||
} | ||
} | ||
|
||
export class RoomNotFoundException extends GameException { | ||
constructor(message: string = 'Room not found') { | ||
super(SocketErrorCode.ROOM_NOT_FOUND, message); | ||
} | ||
} | ||
|
||
export class PlayerNotFoundException extends GameException { | ||
constructor(message: string = 'Player not found') { | ||
super(SocketErrorCode.PLAYER_NOT_FOUND, message); | ||
} | ||
} | ||
|
||
export class BadRequestException extends GameException { | ||
constructor(message: string = 'Bad request') { | ||
super(SocketErrorCode.BAD_REQUEST, message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Catch, ArgumentsHost } from '@nestjs/common'; | ||
import { BaseWsExceptionFilter } from '@nestjs/websockets'; | ||
import { Socket } from 'socket.io'; | ||
import { GameException } from '../exceptions/game.exception'; | ||
|
||
@Catch() | ||
export class WsExceptionFilter extends BaseWsExceptionFilter { | ||
catch(exception: any, host: ArgumentsHost) { | ||
const client = host.switchToWs().getClient<Socket>(); | ||
|
||
if (exception instanceof GameException) { | ||
client.emit('error', { | ||
code: exception.code, | ||
message: exception.message, | ||
}); | ||
} else { | ||
client.emit('error', { | ||
code: 'INTERNAL_ERROR', | ||
message: 'Internal server error', | ||
}); | ||
} | ||
|
||
console.error('WebSocket Error:', exception); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.