Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions backend/src/room/dto/move-index.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IsNotEmpty, IsNumber } from "class-validator";

export class MoveIndexDto {
@IsNotEmpty()
roomId: string;

@IsNumber()
index: number;
}
6 changes: 6 additions & 0 deletions backend/src/room/dto/room-id.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IsNotEmpty } from "class-validator";

export class RoomIdDto {
@IsNotEmpty()
roomId: string;
}
3 changes: 3 additions & 0 deletions backend/src/room/dto/room.dto.ts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

질문지 내용이 없는 것 같습니다

Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ export interface RoomDto {
title: string;
category: string[];
inProgress: boolean;
currentIndex: number;
host: Connection;
status: RoomStatus;
participants: number;
maxParticipants: number;
maxQuestionListLength: number;
questionListId: number;
createdAt: number;
connectionMap: Record<string, Connection>;
}
9 changes: 9 additions & 0 deletions backend/src/room/room.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,21 @@ export class RoomEntity extends Entity {
@Field({ type: "boolean" })
inProgress: boolean;

@Field({ type: "number" })
currentIndex: number;

@Field({ type: "string" })
status: RoomStatus;

@Field({ type: "number" })
maxParticipants: number;

@Field({ type: "number" })
questionListId: number;

@Field({ type: "number" })
maxQuestionListLength: number;

@Field({ type: "number", sortable: true })
createdAt: number;

Expand Down
11 changes: 11 additions & 0 deletions backend/src/room/room.events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,25 @@ export const LISTEN_EVENT = {
LEAVE: "client:room__leave",
FINISH: "client:room__finish",
REACTION: "client:room__reaction",
START_PROGRESS: "client:study__start_progress",
STOP_PROGRESS: "client:study__stop_progress",
NEXT_QUESTION: "client:study__next_question",
CURRENT_INDEX: "client:study__current_index",
MOVE_INDEX: "client:study__move_index",
} as const;

export const EMIT_EVENT = {
CREATE: "server:room__create",
QUIT: "server:room__quit",
FULL: "server:room__full",
JOIN: "server:room__join",
IN_PROGRESS: "server:room__progress",
FINISH: "server:room__finish",
CHANGE_HOST: "server:room__change_host",
REACTION: "server:room__reaction",
START_PROGRESS: "server:study__start_progress",
STOP_PROGRESS: "server:study__stop_progress",
NEXT_QUESTION: "server:study__next_question",
CURRENT_INDEX: "server:study__current_index",
MOVE_INDEX: "server:study__move_index",
} as const;
73 changes: 70 additions & 3 deletions backend/src/room/room.gateway.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {
WebSocketGateway,
ConnectedSocket,
MessageBody,
OnGatewayDisconnect,
SubscribeMessage,
MessageBody,
ConnectedSocket,
WebSocketGateway,
} from "@nestjs/websockets";
import "dotenv/config";
import { Socket } from "socket.io";
Expand All @@ -20,6 +20,8 @@ import { RoomCreateService } from "@/room/services/room-create.service";
import { RoomJoinService } from "@/room/services/room-join.service";
import { websocketConfig } from "@/websocket/websocket.config";
import { FinishRoomDto } from "@/room/dto/finish-room.dto";
import { RoomIdDto } from "@/room/dto/room-id.dto";
import { MoveIndexDto } from "@/room/dto/move-index.dto";

@WebSocketGateway(websocketConfig)
export class RoomGateway implements OnGatewayDisconnect {
Expand Down Expand Up @@ -84,4 +86,69 @@ export class RoomGateway implements OnGatewayDisconnect {
reactionType: dto.reactionType,
});
}

@SubscribeMessage(LISTEN_EVENT.START_PROGRESS)
public async handleStartProgress(
@ConnectedSocket() client: Socket,
@MessageBody() dto: RoomIdDto
) {
return this.toggleProgress(dto.roomId, client.id, true, EMIT_EVENT.START_PROGRESS);
}

@SubscribeMessage(LISTEN_EVENT.STOP_PROGRESS)
public async handleStopProgress(
@ConnectedSocket() client: Socket,
@MessageBody() dto: RoomIdDto
) {
return this.toggleProgress(dto.roomId, client.id, false, EMIT_EVENT.STOP_PROGRESS);
}

@SubscribeMessage(LISTEN_EVENT.NEXT_QUESTION)
public async handleNextQuestion(
@ConnectedSocket() client: Socket,
@MessageBody() dto: RoomIdDto
) {
this.socketService.emitToRoom(dto.roomId, EMIT_EVENT.NEXT_QUESTION, {
currentIndex: await this.roomService.increaseIndex(dto.roomId, client.id),
});
}

@SubscribeMessage(LISTEN_EVENT.CURRENT_INDEX)
public async handleCurrentIndex(
@ConnectedSocket() client: Socket,
@MessageBody() dto: RoomIdDto
) {
this.socketService.emitToRoom(dto.roomId, EMIT_EVENT.CURRENT_INDEX, {
currentIndex: await this.roomService.getIndex(dto.roomId),
});
}

@SubscribeMessage(LISTEN_EVENT.MOVE_INDEX)
public async handleMoveIndex(
@ConnectedSocket() client: Socket,
@MessageBody() dto: MoveIndexDto
) {
this.socketService.emitToRoom(dto.roomId, EMIT_EVENT.MOVE_INDEX, {
currentIndex: await this.roomService.setIndex(dto.roomId, client.id, dto.index),
});
}

private async toggleProgress(
roomId: string,
socketId: string,
toStatus: boolean,
eventName: string
) {
try {
const status = await this.roomService.setProgress(roomId, socketId, toStatus);
this.socketService.emitToRoom(roomId, eventName, {
status: "success",
inProgress: status,
});
} catch {
this.socketService.emitToRoom(roomId, eventName, {
status: "error",
});
}
}
}
9 changes: 9 additions & 0 deletions backend/src/room/room.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export class RoomRepository {
createdAt: room.createdAt,
host: JSON.parse(room.host),
maxParticipants: room.maxParticipants,
maxQuestionListLength: room.maxQuestionListLength,
questionListId: room.questionListId,
currentIndex: room.currentIndex,
status: room.status,
title: room.title,
id: room.id,
Expand All @@ -43,6 +46,9 @@ export class RoomRepository {
inProgress: room.inProgress,
connectionMap,
createdAt: room.createdAt,
currentIndex: room.currentIndex,
maxQuestionListLength: room.maxQuestionListLength,
questionListId: room.questionListId,
host: JSON.parse(room.host),
participants: Object.keys(connectionMap).length,
maxParticipants: room.maxParticipants,
Expand All @@ -59,8 +65,11 @@ export class RoomRepository {
room.inProgress = dto.inProgress;
room.title = dto.title;
room.status = dto.status;
room.currentIndex = dto.currentIndex;
room.connectionMap = JSON.stringify(dto.connectionMap);
room.maxParticipants = dto.maxParticipants;
room.maxQuestionListLength = dto.maxQuestionListLength;
room.questionListId = dto.questionListId;
room.createdAt = Date.now();
room.host = JSON.stringify(dto.host);

Expand Down
2 changes: 2 additions & 0 deletions backend/src/room/services/room-create.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export class RoomCreateService {
participants: 0,
questionListContents,
createdAt: currentTime,
maxQuestionListLength: questionListContents.length,
currentIndex: 0,
host: {
socketId: dto.socketId,
nickname,
Expand Down
16 changes: 14 additions & 2 deletions backend/src/room/services/room-join.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { RoomRepository } from "@/room/room.repository";
import { RoomDto } from "@/room/dto/room.dto";
import { JoinRoomInternalDto } from "@/room/dto/join-room.dto";
import { WebsocketRepository } from "@/websocket/websocket.repository";
import { QuestionListRepository } from "@/question-list/question-list.repository";

@Injectable()
export class RoomJoinService {
public constructor(
private readonly roomRepository: RoomRepository,
private readonly socketService: WebsocketService,
private readonly socketRepository: WebsocketRepository
private readonly socketRepository: WebsocketRepository,
private readonly questionListRepository: QuestionListRepository
) {}

public async joinRoom(dto: JoinRoomInternalDto) {
Expand All @@ -24,6 +26,8 @@ export class RoomJoinService {

if (!room) throw new Error("RoomEntity Not found");

if (room.inProgress) return socket.emit(EMIT_EVENT.IN_PROGRESS, {});

if (this.isFullRoom(room)) return socket.emit(EMIT_EVENT.FULL, {});

socket.join(roomId);
Expand All @@ -39,8 +43,16 @@ export class RoomJoinService {
await this.roomRepository.setRoom(room);

room.connectionMap[socketId] = undefined;

const questionListContents = await this.questionListRepository.getContentsByQuestionListId(
room.questionListId
);

// TODO: 성공 / 실패 여부를 전송하는데 있어서 결과에 따라 다르게 해야하는데.. 어떻게 관심 분리를 할까?
socket.emit(EMIT_EVENT.JOIN, room);
socket.emit(EMIT_EVENT.JOIN, {
...room,
questionListContents,
});
}

private isFullRoom(room: RoomDto): boolean {
Expand Down
46 changes: 46 additions & 0 deletions backend/src/room/services/room.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,52 @@ export class RoomService {
.sort((a, b) => b.createdAt - a.createdAt);
}

public async setProgress(roomId: string, socketId: string, status: boolean) {
const room = await this.roomRepository.getRoom(roomId);

if (!room) throw new Error("cannot set progress");
if (room.host.socketId !== socketId) throw new Error("only host can set process");

room.inProgress = status;
if (!room.inProgress) room.currentIndex = 0;
await this.roomRepository.setRoom(room);
return status;
}

public async setIndex(roomId: string, socketId: string, index: number) {
const room = await this.roomRepository.getRoom(roomId);

// TODO : 리팩토링 할 필요가 있어보임.
if (
!room ||
!room.inProgress ||
room.host.socketId !== socketId ||
index < 0 ||
index >= room.maxQuestionListLength
)
return -1;

room.currentIndex = index;
await this.roomRepository.setRoom(room);
return index;
}

public async getIndex(roomId: string) {
return (await this.roomRepository.getRoom(roomId)).currentIndex;
}

public async increaseIndex(roomId: string, socketId: string) {
const room = await this.roomRepository.getRoom(roomId);

if (!room || room.host.socketId !== socketId || !room.inProgress) return -1;

const index = await this.setIndex(roomId, socketId, (await this.getIndex(roomId)) + 1);

if (index === -1) return room.maxQuestionListLength - 1;

return index;
}

public async finishRoom(roomId: string) {
await this.roomRepository.removeRoom(roomId);
return roomId;
Expand Down