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

[MERGE] dev to prod-fe #2

Merged
merged 52 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
8bb0700
feat: outgoing message 에 socket.id 추가
hoeeeeeh Nov 30, 2024
e94af4c
feat: question dto 에 socket.id 추가
hoeeeeeh Nov 30, 2024
299da5e
feat: user ip ban 로직 추가
hoeeeeeh Nov 30, 2024
86e9327
feat: 방송/다시보기 존재 여부에 대한 체크 api
i3kae Nov 30, 2024
d24e4af
Merge pull request #251 from boostcampwm-2024/feature-be-#250-ban_user
hoeeeeeh Nov 30, 2024
e875777
Merge pull request #254 from boostcampwm-2024/feature-be-live_replay_…
i3kae Nov 30, 2024
73c706e
fix: init data 형식 수정
hoeeeeeh Dec 2, 2024
e2ab360
Merge pull request #257 from boostcampwm-2024/feature-be-#250-ban_user
hoeeeeeh Dec 2, 2024
905c03a
fix: init data 형식 수정
hoeeeeeh Dec 2, 2024
cce1a34
Merge pull request #259 from boostcampwm-2024/feature-be-#250-ban_user
hoeeeeeh Dec 2, 2024
8175734
refactor: ChatException throw 시, roomId 를 담아서 throw
hoeeeeeh Dec 2, 2024
6a45640
Merge pull request #261 from boostcampwm-2024/feature-be-#250-ban_user
hoeeeeeh Dec 2, 2024
8fb89c6
feat: Chat Exception 세분화
hoeeeeeh Dec 2, 2024
a5068ab
feat: Chat Exception 세분화
hoeeeeeh Dec 2, 2024
aebfe14
Merge pull request #264 from boostcampwm-2024/feature-be-#250-ban_user
hoeeeeeh Dec 2, 2024
b47e98c
refactor : user ban 을 x-forwarded 에서 userAgent 로 변경
hoeeeeeh Dec 2, 2024
c4cbf1b
Merge pull request #268 from boostcampwm-2024/feature-be-#250-ban_user
hoeeeeeh Dec 2, 2024
976ccff
chore: API reponse 변경 및 기본 공지 변경
i3kae Dec 2, 2024
583db30
fix: 치지직 mock 데이터에 맞게 세션 확인 api가 동작하도록 수정
i3kae Dec 2, 2024
5ea5ded
feat: 라이브 이미지 url을 방송 시작 시 삽입
i3kae Dec 3, 2024
ea72aa7
chore: 다시보기 영상이 등록 순으로 정렬되도록 수정
i3kae Dec 3, 2024
d173cc7
refactor: node-media-server 업데이트
i3kae Dec 3, 2024
4ab309e
refactor: node media server에 맞춰 타입 추가
i3kae Dec 3, 2024
0706388
Merge pull request #276 from boostcampwm-2024/feature-be-#231-live_th…
i3kae Dec 3, 2024
4321e2a
feat: 개발자용 데이터 수정 api 추가
i3kae Dec 3, 2024
e21bce2
Merge pull request #281 from boostcampwm-2024/feature-be-#231-live_th…
i3kae Dec 3, 2024
efb7b0a
Update README.md
spearStr Dec 3, 2024
4957375
Update README.md
spearStr Dec 3, 2024
8853a6d
Update README.md
spearStr Dec 3, 2024
a410a7a
fix: rtmp 버그 수정
i3kae Dec 3, 2024
80c9612
Update README.md
spearStr Dec 3, 2024
bb83da5
Update README.md
spearStr Dec 3, 2024
835058b
refactor: 라이브 / 다시보기가 각각 시작 날짜, 종료 날짜 순으로 정렬되도록 수정
i3kae Dec 3, 2024
466754b
Update README.md
jsk3342 Dec 3, 2024
f21ca57
Update README.md
jsk3342 Dec 3, 2024
65a4adc
Update README.md
gominzip Dec 3, 2024
041961c
docs: 리드미 구성 및 표로 수정
gominzip Dec 3, 2024
b3a6675
docs: 기술정리 문장 수정
gominzip Dec 3, 2024
7a2e835
Update README.md
spearStr Dec 4, 2024
ffc2156
refactor: chat server 의 User 를 redis 로 이동
hoeeeeeh Dec 4, 2024
92f5ea4
Merge remote-tracking branch 'refs/remotes/origin/dev-be' into dev-be
hoeeeeeh Dec 4, 2024
8bf6737
Update README.md
gominzip Dec 4, 2024
307832d
refactor: chat server blacklist 로직 수정
hoeeeeeh Dec 4, 2024
62163d4
docs: 핵심 기술 정리 업데이트
gominzip Dec 4, 2024
d5417f0
docs: 목차 수정
gominzip Dec 4, 2024
f25b062
Update README.md
gominzip Dec 4, 2024
d9f2567
Update README.md
hoeeeeeh Dec 4, 2024
8c70cc4
Update README.md
hoeeeeeh Dec 4, 2024
c1e14b4
feat: check heartbeat
hoeeeeeh Dec 4, 2024
da5f390
docs: 기술 스택 수정
gominzip Dec 5, 2024
51f7b1c
Merge pull request #294 from boostcampwm-2024/dev-be
hoeeeeeh Dec 30, 2024
2a583b7
Merge pull request #297 from boostcampwm-2024/dev-fe
gominzip Dec 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 111 additions & 78 deletions README.md

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions backend/chatServer/src/chat/chat.error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { HttpStatus } from '@nestjs/common';
import { WsException } from '@nestjs/websockets';

class ChatException extends WsException {
statusCode: number;
constructor({ statusCode, message } : ChatError , public roomId?: string) {
super({ statusCode, message, roomId });
this.statusCode = statusCode;
}

getError() {
return {
statusCode: this.statusCode,
msg: this.message,
roomId: this.roomId || null,
};
}
}

interface ChatError {
statusCode: number;
message: string;
}

const CHATTING_SOCKET_ERROR = {
ROOM_EMPTY: {
statusCode: HttpStatus.BAD_REQUEST,
message: '유저가 참여하고 있는 채팅방이 없습니다.'
},

ROOM_EXISTED: {
statusCode: HttpStatus.BAD_REQUEST,
message: '이미 존재하는 방입니다.'
},

INVALID_USER: {
statusCode: HttpStatus.UNAUTHORIZED,
message: '유효하지 않는 유저입니다.'
},

UNAUTHORIZED: {
statusCode: HttpStatus.UNAUTHORIZED,
message: '해당 명령에 대한 권한이 없습니다.'
},

QUESTION_EMPTY: {
statusCode: HttpStatus.BAD_REQUEST,
message: '유효하지 않은 질문입니다.'
},

BAN_USER: {
statusCode: HttpStatus.FORBIDDEN,
message: '호스트에 의해 밴 당한 유저입니다.'
},

MSG_TOO_LONG:{
statusCode: HttpStatus.NOT_ACCEPTABLE,
message: '메세지의 내용이 없거나, 길이가 150자를 초과했습니다.'
}


};
export { CHATTING_SOCKET_ERROR, ChatException };

57 changes: 42 additions & 15 deletions backend/chatServer/src/chat/chat.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,35 @@ import {
OnGatewayConnection,
OnGatewayDisconnect,
MessageBody,
ConnectedSocket,
ConnectedSocket
} from '@nestjs/websockets';
import { UseGuards } from '@nestjs/common';
import { Server, Socket } from 'socket.io';
import {
CHATTING_SOCKET_DEFAULT_EVENT,
CHATTING_SOCKET_RECEIVE_EVENT, CHATTING_SOCKET_SEND_EVENT
CHATTING_SOCKET_DEFAULT_EVENT, CHATTING_SOCKET_RECEIVE_EVENT, CHATTING_SOCKET_SEND_EVENT
} from '../event/constants';
import {
BanUserIncomingMessageDto,
NormalIncomingMessageDto, NoticeIncomingMessageDto, QuestionDoneIncomingMessageDto, QuestionIncomingMessageDto
} from '../event/dto/IncomingMessage.dto';
import { JoiningRoomDto } from '../event/dto/JoiningRoom.dto';
import { RoomService } from '../room/room.service';
import { createAdapter } from '@socket.io/redis-adapter';
import { HostGuard, MessageGuard } from './chat.guard';
import { BlacklistGuard, HostGuard, MessageGuard } from './chat.guard';
import { LeavingRoomDto } from '../event/dto/LeavingRoom.dto';
import {
NormalOutgoingMessageDto,
NoticeOutgoingMessageDto,
QuestionOutgoingMessageDto
} from '../event/dto/OutgoingMessage.dto';
import { QuestionDto } from '../event/dto/Question.dto';
import { ChatException, CHATTING_SOCKET_ERROR } from './chat.error';

@WebSocketGateway({ cors: true })
@WebSocketGateway({
cors: true,
pingInterval: 30000,
pingTimeout: 10000,
})
export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
constructor(private roomService: RoomService) {};

Expand All @@ -46,7 +51,7 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa

async handleConnection(client: Socket) {
console.log(`Client connected: ${client.id}`);
const user = await this.roomService.createUser(client.id);
const user = await this.roomService.createUser(client);
console.log(user);

/*
Expand All @@ -69,6 +74,7 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
}

// 특정 방에 참여하기 위한 메서드
@UseGuards(BlacklistGuard)
@SubscribeMessage(CHATTING_SOCKET_DEFAULT_EVENT.JOIN_ROOM)
async handleJoinRoom(client: Socket, payload: JoiningRoomDto) {
const { roomId, userId } = payload;
Expand All @@ -93,17 +99,20 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
}

// 방에 NORMAL 메시지를 보내기 위한 메서드
@UseGuards(MessageGuard)
@UseGuards(MessageGuard, BlacklistGuard)
@SubscribeMessage(CHATTING_SOCKET_SEND_EVENT.NORMAL)
async handleNormalMessage(@ConnectedSocket() client: Socket, @MessageBody() payload: NormalIncomingMessageDto) {
const { roomId, userId, msg } = payload;
const user = await this.roomService.getUserByClientId(client.id);
const normalOutgoingMessage: Omit<NormalOutgoingMessageDto, 'owner'> = {
roomId,
...user,
nickname: user.nickname,
color: user.color,
entryTime: user.entryTime,
msg,
msgTime: new Date().toISOString(),
msgType: 'normal'
msgType: 'normal',
socketId: client.id
};
console.log('Normal Message Come In: ', normalOutgoingMessage);
const hostId = await this.roomService.getHostOfRoom(roomId);
Expand All @@ -121,18 +130,21 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
}

// 방에 QUESTION 메시지를 보내기 위한 메서드
@UseGuards(MessageGuard)
@UseGuards(MessageGuard,BlacklistGuard)
@SubscribeMessage(CHATTING_SOCKET_SEND_EVENT.QUESTION)
async handleQuestionMessage(@ConnectedSocket() client: Socket, @MessageBody() payload: QuestionIncomingMessageDto) {
const { roomId, msg } = payload;
const user = await this.roomService.getUserByClientId(client.id);
const questionWithoutId: Omit<QuestionDto, 'questionId'> = {
roomId,
...user,
nickname: user.nickname,
color: user.color,
entryTime: user.entryTime,
msg,
msgTime: new Date().toISOString(),
msgType: 'question',
questionDone: false
questionDone: false,
socketId: client.id
};

const question: QuestionOutgoingMessageDto = await this.roomService.addQuestion(roomId, questionWithoutId);
Expand All @@ -150,19 +162,34 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
}

// 방에 NOTICE 메시지를 보내기 위한 메서드
@UseGuards(MessageGuard)
@UseGuards(HostGuard)
@UseGuards(MessageGuard, HostGuard)
@SubscribeMessage(CHATTING_SOCKET_SEND_EVENT.NOTICE)
async handleNoticeMessage(@ConnectedSocket() client: Socket, @MessageBody() payload: NoticeIncomingMessageDto) {
const { roomId, msg } = payload;
const user = await this.roomService.getUserByClientId(client.id);
const noticeOutgoingMessage: NoticeOutgoingMessageDto = {
roomId,
...user,
nickname: user.nickname,
color: user.color,
entryTime: user.entryTime,
msg,
msgTime: new Date().toISOString(),
msgType: 'notice'
};
this.server.to(roomId).emit(CHATTING_SOCKET_RECEIVE_EVENT.NOTICE, noticeOutgoingMessage);
}

@UseGuards(HostGuard)
@SubscribeMessage(CHATTING_SOCKET_DEFAULT_EVENT.BAN_USER)
async handleBanUserMessage(@ConnectedSocket() client: Socket, @MessageBody() payload: BanUserIncomingMessageDto) {
const { roomId, socketId } = payload;
const banUser = await this.roomService.getUserByClientId(socketId);
console.log('banUSer = ', banUser);
if(!banUser) throw new ChatException(CHATTING_SOCKET_ERROR.INVALID_USER, roomId);
const { address, userAgent } = banUser;
if(!userAgent) throw new ChatException(CHATTING_SOCKET_ERROR.INVALID_USER, roomId);

await this.roomService.addUserToBlacklist(roomId, address, userAgent);
console.log(await this.roomService.getUserBlacklist(roomId, address));
}
}
37 changes: 35 additions & 2 deletions backend/chatServer/src/chat/chat.guard.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { RoomService } from '../room/room.service';
import { Socket } from 'socket.io';

import { ChatException, CHATTING_SOCKET_ERROR } from './chat.error';

@Injectable()
export class MessageGuard implements CanActivate {
constructor() {};
canActivate(context: ExecutionContext): boolean {
const payload = context.switchToWs().getData();
const { msg } = payload;
return !!msg && msg.length <= 150;
if(!!msg && msg.length <= 150) return true;
throw new ChatException(CHATTING_SOCKET_ERROR.MSG_TOO_LONG);
}
}

Expand All @@ -19,6 +23,35 @@ export class HostGuard implements CanActivate {
const { roomId, userId } = payload;
const hostId = await this.roomService.getHostOfRoom(roomId);
console.log('hostGuard:', hostId, userId);
return hostId === userId;
if (hostId === userId) return true;
throw new ChatException(CHATTING_SOCKET_ERROR.UNAUTHORIZED, roomId);
}
}

@Injectable()
export class BlacklistGuard implements CanActivate {
constructor(private roomService: RoomService) {};
async canActivate(context: ExecutionContext) {
const payload = context.switchToWs().getData();
const { roomId } = payload;

const client: Socket = context.switchToWs().getClient<Socket>();
const address = client.handshake.address.replaceAll('::ffff:', '');
const userAgent = client.handshake.headers['user-agent'];

if(!userAgent) throw new ChatException(CHATTING_SOCKET_ERROR.INVALID_USER, roomId);
const isValidUser = await this.whenJoinRoom(roomId, address, userAgent);

if(!isValidUser) throw new ChatException(CHATTING_SOCKET_ERROR.BAN_USER, roomId);
return true;
}

async whenJoinRoom(roomId: string, address: string, userAgent: string) {
console.log(roomId, address, userAgent);
const blacklistInRoom = await this.roomService.getUserBlacklist(roomId, address);
console.log(blacklistInRoom);
const isInBlacklistUser = blacklistInRoom.some((bannedUserAgent) => bannedUserAgent === userAgent);
console.log('blacklistInRoom:', isInBlacklistUser);
return !isInBlacklistUser;
}
}
4 changes: 2 additions & 2 deletions backend/chatServer/src/chat/chat.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Module } from '@nestjs/common';
import { ChatGateway } from './chat.gateway';
import { RoomModule } from '../room/room.module';
import { MessageGuard } from './chat.guard';
import { BlacklistGuard, HostGuard, MessageGuard } from './chat.guard';

@Module({
imports: [RoomModule],
providers: [ChatGateway, MessageGuard],
providers: [ChatGateway, MessageGuard, BlacklistGuard, HostGuard],
})
export class ChatModule {}
29 changes: 2 additions & 27 deletions backend/chatServer/src/event/constants.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { HttpStatus } from '@nestjs/common';

const CHATTING_SOCKET_DEFAULT_EVENT = {
JOIN_ROOM: 'join_room',
LEAVE_ROOM: 'leave_room',
BAN_USER: 'ban_user',
};

const CHATTING_SOCKET_RECEIVE_EVENT = {
Expand All @@ -20,28 +19,4 @@ const CHATTING_SOCKET_SEND_EVENT = {
NOTICE: 'send_notice'
};

const CHATTING_SOCKET_ERROR = {
ROOM_EMPTY : {
statusCode: HttpStatus.BAD_REQUEST,
message: '유저가 참여하고 있는 채팅방이 없습니다.'
},

ROOM_EXISTED: {
statusCode: HttpStatus.BAD_REQUEST,
message: '이미 존재하는 방입니다.'
},

INVALID_USER: {
statusCode: HttpStatus.UNAUTHORIZED,
message: '유효하지 않는 유저입니다.'
},

QUESTION_EMPTY: {
statusCode: HttpStatus.BAD_REQUEST,
message: '유효하지 않은 질문입니다.'
},


};

export { CHATTING_SOCKET_DEFAULT_EVENT, CHATTING_SOCKET_SEND_EVENT, CHATTING_SOCKET_RECEIVE_EVENT, CHATTING_SOCKET_ERROR};
export { CHATTING_SOCKET_DEFAULT_EVENT, CHATTING_SOCKET_SEND_EVENT, CHATTING_SOCKET_RECEIVE_EVENT};
8 changes: 7 additions & 1 deletion backend/chatServer/src/event/dto/IncomingMessage.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@ class NoticeIncomingMessageDto extends DefaultIncomingMessageDto {
msg: string = '';
}

class BanUserIncomingMessageDto extends DefaultIncomingMessageDto {
userId: string = '';
socketId: string = '';
}



export {
NormalIncomingMessageDto,
QuestionIncomingMessageDto,
QuestionDoneIncomingMessageDto,
DefaultIncomingMessageDto,
NoticeIncomingMessageDto
NoticeIncomingMessageDto,
BanUserIncomingMessageDto
};
10 changes: 9 additions & 1 deletion backend/chatServer/src/event/dto/OutgoingMessage.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,31 @@ class DefaultOutgoingMessageDto {
roomId: string = '';
nickname: string = '';
color: string = '';
entryTime: string = '';
msgTime: string = new Date().toISOString();
}

class NormalOutgoingMessageDto extends DefaultOutgoingMessageDto {
msg: string = '';
msgType: OutgoingMessageType = 'normal';
owner: WhoAmI = 'user';
socketId: string = '';
}

class QuestionOutgoingMessageDto extends DefaultOutgoingMessageDto {
msg: string = '';
questionId: number = -1;
questionDone: boolean = false;
msgType: OutgoingMessageType = 'question';
socketId: string = '';
}

class QuestionDoneOutgoingMessageDto extends QuestionOutgoingMessageDto {}
class QuestionDoneOutgoingMessageDto extends DefaultOutgoingMessageDto {
msg: string = '';
questionId: number = -1;
questionDone: boolean = false;
msgType: OutgoingMessageType = 'question';
}

class NoticeOutgoingMessageDto extends DefaultOutgoingMessageDto {
msg: string = '';
Expand Down
2 changes: 2 additions & 0 deletions backend/chatServer/src/event/dto/Question.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ class QuestionDto {
roomId: string = '';
nickname: string = '';
color: string = '';
entryTime: string = '';
msg: string = '';
msgTime: string = new Date().toISOString();
msgType: OutgoingMessageType = 'question';
questionId: number = -1;
socketId: string = '';
questionDone: boolean = false;
}

Expand Down
Loading
Loading