Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE]: 서버 리펙토링 및 시그널링 서버 에러 제거 #121

Merged
merged 10 commits into from
Nov 27, 2023
2 changes: 2 additions & 0 deletions backEnd/center/src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ export const EVENT = {
REGISTER: 'register',
SIGNALING: 'signaling',
};

export const USE_FULL = 100;
7 changes: 3 additions & 4 deletions backEnd/center/src/events/events.service.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { InjectRedis } from '@liaoliaots/nestjs-redis';
import { HttpCode, HttpStatus, Injectable, OnModuleInit } from '@nestjs/common';
import { HttpStatus, Injectable, OnModuleInit } from '@nestjs/common';
import Redis from 'ioredis';
import { ResponseUrlDto } from 'src/connections/dto/response-url.dto';
import { JoinRoomDto } from 'src/connections/dto/join-room.dto';
import {
URLNotFoundException,
ValidateDtoException,
} from 'src/common/exception/exception';
import { ERRORS, EVENT } from 'src/common/utils';
import { ERRORS, EVENT, USE_FULL } from 'src/common/utils';
import { ResponseDto } from 'src/common/dto/common-response.dto';

@Injectable()
Expand Down Expand Up @@ -55,7 +54,7 @@ export class EventsService implements OnModuleInit {

private handleSignaling(url: string, usages: number) {
const nextServer = this.returnUrl;
const minUsages = this.serverToCpus.get(nextServer);
const minUsages = this.serverToCpus.get(nextServer) || USE_FULL;

if (usages < minUsages) {
this.returnUrl = url;
Expand Down
4 changes: 3 additions & 1 deletion backEnd/chat/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ChatGateway } from './chat/chat.gateway';
import { ChatService } from './chat/chat.service';
import { ChatModule } from './chat/chat.module';

@Module({
imports: [
Expand All @@ -21,8 +22,9 @@ import { ChatService } from './chat/chat.service';
}),
inject: [ConfigService],
}),
ChatModule,
],
controllers: [AppController],
providers: [AppService, ChatGateway, ChatService],
providers: [AppService],
})
export class AppModule {}
76 changes: 76 additions & 0 deletions backEnd/chat/src/chat/chat.gateway.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ChatGateway } from './chat.gateway';
import { ChatService } from './chat.service';
import Redis from 'ioredis';
import { RedisModule, getRedisToken } from '@liaoliaots/nestjs-redis';
import { MessageDto } from './dto/message.dto';
import { Socket } from 'socket.io';
import { WsException } from '@nestjs/websockets';

describe('ChatGateway', () => {
let gateway: ChatGateway;
let chatService: ChatService;
let redisClient: Redis;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
RedisModule.forRoot({
config: {
host: 'localhost',
port: 6379,
},
}),
],
providers: [ChatGateway, ChatService],
}).compile();

gateway = module.get<ChatGateway>(ChatGateway);
chatService = module.get<ChatService>(ChatService);
redisClient = module.get<Redis>(getRedisToken('default'));
});

afterEach(async () => {
await redisClient.flushall();
});

describe('Redis', () => {
it('레디스와 연결에 성공한다.', async () => {
expect(redisClient).toBeDefined();
const response = await redisClient.ping();
expect(response).toBe('PONG');
});
});

describe('sendMessage', () => {
it('메시지를 보냈을때 room 정보가 없으면 예외가 발생한다.', async () => {
//GIVEN
const testMessageDto: MessageDto = {
room: '',
message: 'testMessage',
};
const testSocket = { id: '12345' } as unknown as Socket;

// WHEN
const messageHandling = gateway.handleMessage(testMessageDto, testSocket);

// THEN
await expect(messageHandling).rejects.toThrow(WsException);
});

it('메시지를 보냈을때 message 정보가 없으면 예외가 발생한다.', async () => {
//GIVEN
const testMessageDto: MessageDto = {
room: 'testRoom',
message: '',
};
const testSocket = { id: '12345' } as unknown as Socket;

// WHEN
const messageHandling = gateway.handleMessage(testMessageDto, testSocket);

// THEN
await expect(messageHandling).rejects.toThrow(WsException);
});
});
});
36 changes: 31 additions & 5 deletions backEnd/chat/src/chat/chat.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import {
ConnectedSocket,
MessageBody,
OnGatewayConnection,
OnGatewayDisconnect,
SubscribeMessage,
WebSocketGateway,
WebSocketServer,
WsException,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import { Logger } from '@nestjs/common';
Expand All @@ -14,11 +16,11 @@ import { JoinRoomDto } from './dto/join-room.dto';
import { LeaveRoomDto } from './dto/leave-room.dto';
import { MessageDto } from './dto/message.dto';
import * as os from 'os';
import { SOCKET, SOCKET_EVENT } from 'src/commons/utils';
import { ERRORS, SOCKET, SOCKET_EVENT } from '../commons/utils';
import { ChatService } from './chat.service';

@WebSocketGateway({ namespace: SOCKET.NAME_SPACE, cors: true })
export class ChatGateway implements OnGatewayConnection {
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer()
server: Server;

Expand All @@ -41,11 +43,17 @@ export class ChatGateway implements OnGatewayConnection {
this.logger.log(`Instance ${this.instanceId} - connected: ${socket.id}`);
}

handleDisconnect(socket: Socket) {
this.logger.log(`Instance ${this.instanceId} - disconnected: ${socket.id}`);
}

@SubscribeMessage(SOCKET_EVENT.JOIN_ROOM)
handleJoin(
@MessageBody() data: JoinRoomDto,
@ConnectedSocket() socket: Socket,
) {
this.logger.log(`Instance ${this.instanceId} - joinRoom: ${socket.id}`);

const { room } = data;
this.chatService.validateRoom(room);

Expand All @@ -71,6 +79,8 @@ export class ChatGateway implements OnGatewayConnection {
@MessageBody() data: LeaveRoomDto,
@ConnectedSocket() socket: Socket,
) {
this.logger.log(`Instance ${this.instanceId} - leaveRoom: ${socket.id}`);

const { room } = data;
this.chatService.validateRoom(room);

Expand All @@ -86,15 +96,31 @@ export class ChatGateway implements OnGatewayConnection {
}

@SubscribeMessage(SOCKET_EVENT.SEND_MESSAGE)
async handleMessage(@MessageBody() data: MessageDto) {
const { room, message } = data;
async handleMessage(
@MessageBody() data: MessageDto,
@ConnectedSocket() socket: Socket,
) {
this.logger.log(`Instance ${this.instanceId} - sendMessage: ${socket.id}`);

const { room, message, nickname } = data;

this.chatService.validateRoom(room);
this.chatService.validateMessage(message);
this.chatService.validateNickname(nickname);

const response = {
message: message,
nickname: nickname,
socketId: socket.id,
};
this.publisherClient.publish(room, JSON.stringify(response));

try {
await this.publisherClient.publish(room, JSON.stringify(response));
} catch (error) {
throw new WsException({
statusCode: ERRORS.FAILED_PUBLISHING.statusCode,
message: ERRORS.FAILED_PUBLISHING.message,
});
}
}
}
6 changes: 6 additions & 0 deletions backEnd/chat/src/chat/chat.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Module } from '@nestjs/common';
import { ChatGateway } from './chat.gateway';
import { ChatService } from './chat.service';

@Module({ providers: [ChatGateway, ChatService] })
export class ChatModule {}
21 changes: 21 additions & 0 deletions backEnd/chat/src/chat/chat.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ChatService } from './chat.service';
import { WsException } from '@nestjs/websockets';

describe('ChatService', () => {
let service: ChatService;
Expand All @@ -15,4 +16,24 @@ describe('ChatService', () => {
it('should be defined', () => {
expect(service).toBeDefined();
});

describe('validateRoom', () => {
it('방 이름을 입력하면 예외가 발생하지 않는다.', () => {
expect(() => service.validateRoom('room1')).not.toThrow();
});

it('방 이름을 입력하지 않으면 예외가 발생한다.', () => {
expect(() => service.validateRoom('')).toThrow(WsException);
});
});

describe('validateMessage', () => {
it('메시지를 입력하면 예외가 발생하지 않는다.', () => {
expect(() => service.validateMessage('message1')).not.toThrow();
});

it('메시지를 입력하지 않으면 예외가 발생한다.', () => {
expect(() => service.validateMessage('')).toThrow(WsException);
});
});
});
11 changes: 10 additions & 1 deletion backEnd/chat/src/chat/chat.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable, HttpStatus } from '@nestjs/common';
import { WsException } from '@nestjs/websockets';
import { ERRORS } from 'src/commons/utils';
import { ERRORS } from '../commons/utils';

@Injectable()
export class ChatService {
Expand All @@ -21,4 +21,13 @@ export class ChatService {
});
}
}

validateNickname(nickname: string) {
if (!nickname) {
throw new WsException({
statusCode: ERRORS.ROOM_EMPTY.statusCode,
message: ERRORS.ROOM_EMPTY.message,
});
}
}
}
1 change: 1 addition & 0 deletions backEnd/chat/src/chat/dto/message.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export class MessageDto {
room: string;
message: string;
nickname: string;
}
8 changes: 8 additions & 0 deletions backEnd/chat/src/commons/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export const SOCKET_EVENT = {
};

export const ERRORS = {
NICKNAME_EMPTY: {
statusCode: HttpStatus.BAD_REQUEST,
message: '닉네임을 입력해주세요.',
},
ROOM_EMPTY: {
statusCode: HttpStatus.BAD_REQUEST,
message: '방 이름을 입력해주세요.',
Expand All @@ -22,4 +26,8 @@ export const ERRORS = {
statusCode: HttpStatus.BAD_REQUEST,
message: '메시지를 입력해주세요.',
},
FAILED_PUBLISHING: {
statusCode: HttpStatus.BAD_REQUEST,
message: '메시지를 PUB하는데 실패했습니다.',
},
};
5 changes: 3 additions & 2 deletions backEnd/signaling/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { WebRtcGateway } from './webRTC/web-rtc.gateway';
import { WinstonLogger } from './common/logger/winstonLogger.service';
import { RedisModule } from '@liaoliaots/nestjs-redis';
import { EventsModule } from './events/events.module';
import { WebRtcModule } from './webRTC/web-rtc.module';

@Module({
imports: [
Expand All @@ -23,8 +23,9 @@ import { EventsModule } from './events/events.module';
inject: [ConfigService],
}),
EventsModule,
WebRtcModule,
],
controllers: [AppController],
providers: [AppService, WebRtcGateway, WinstonLogger],
providers: [AppService, WinstonLogger],
})
export class AppModule {}
28 changes: 27 additions & 1 deletion backEnd/signaling/src/common/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { HttpStatus } from '@nestjs/common';

export const SOCKET = {
NAME_SPACE: 'signaling',
MAXIMUM: 4,
ROOM_FULL: 4,
ROOM_EMPTY: 0,
};

export const SOCKET_EVENT = {
Expand All @@ -18,3 +21,26 @@ export const SOCKET_EVENT = {
GET_ANSWER: 'getAnswer',
GET_CANDIDATE: 'getCandidate',
};

export const ERRORS = {
ROOM_FULL: {
statusCode: HttpStatus.BAD_REQUEST,
message: '해당 방에 인원이 가득찼습니다.',
},
FAIL_JOIN_ROOM: {
statusCode: HttpStatus.BAD_REQUEST,
message: 'ROOM JOIN에 실패하였습니다.',
},
FAIL_OFFER: {
statusCode: HttpStatus.BAD_REQUEST,
message: 'OFFER에 실패하였습니다.',
},
FAIL_ANSWER: {
statusCode: HttpStatus.BAD_REQUEST,
message: 'ANSWER에 실패하였습니다.',
},
FAIL_CANDIDATE: {
statusCode: HttpStatus.BAD_REQUEST,
message: 'CANDIDATE에 실패하였습니다.',
},
};
3 changes: 1 addition & 2 deletions backEnd/signaling/src/events/events.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Module } from '@nestjs/common';
import { EventsService } from './events.service';
import { WebRtcGateway } from 'src/webRTC/web-rtc.gateway';

@Module({
providers: [EventsService, WebRtcGateway],
providers: [EventsService],
exports: [EventsService],
})
export class EventsModule {}
Loading