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
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class TypeormInterviewDocsEntity
@IsString()
userId: string;

@Column({ length: 100 })
@Column({ length: 200 })
@IsString()
videoUrl: string;

Expand Down
4 changes: 3 additions & 1 deletion backend/socket/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@nestjs/platform-express": "^9.0.0",
"@nestjs/platform-socket.io": "^9.2.0",
"@nestjs/websockets": "^9.2.0",
"@socket.io/redis-adapter": "^8.0.0",
"@types/aws-sdk": "^2.7.0",
"aws-sdk": "^2.1267.0",
"class-transformer": "^0.5.1",
Expand All @@ -38,10 +39,11 @@
"fs": "^0.0.1-security",
"joi": "^17.7.0",
"lint-staged": "^13.0.4",
"redis": "^4.5.1",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
"socket.io": "^4.5.3",
"socket.io": "^4.5.4",
"uuid": "^9.0.0"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion backend/socket/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { envConfig } from './config/env.config';
import { envConfig } from '@config';
import { RoomModule } from './room/room.module';

@Module({
Expand Down
2 changes: 2 additions & 0 deletions backend/socket/src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './env.config';
export * from './redis.adapter';
22 changes: 22 additions & 0 deletions backend/socket/src/config/redis.adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { IoAdapter } from '@nestjs/platform-socket.io';
import { ServerOptions } from 'socket.io';
import { createAdapter } from '@socket.io/redis-adapter';
import { createClient } from 'redis';

export const pubClient = createClient({ url: process.env.REDIS_URL });
const subClient = pubClient.duplicate();

export class RedisIoAdapter extends IoAdapter {
private adapterConstructor: ReturnType<typeof createAdapter>;

async connectToRedis(): Promise<void> {
await Promise.all([pubClient.connect(), subClient.connect()]);
this.adapterConstructor = createAdapter(pubClient, subClient);
}

createIOServer(port: number, options?: ServerOptions): any {
const server = super.createIOServer(port, options);
server.adapter(this.adapterConstructor);
return server;
}
}
8 changes: 4 additions & 4 deletions backend/socket/src/constant/event.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ export enum EVENT {
}

export enum ERROR_MSG {
FULL_ROOM = 'full_room',
NO_ROOM = 'no_room',
BUSY_ROOM = 'busy_room',
NOT_ENOUGHT_USER = 'not_enough_user',
FULL_ROOM = '방이 꽉 찼습니다.',
NO_ROOM = '없는 방입니다.',
BUSY_ROOM = '현재 면접이 진행중입니다.',
NOT_ENOUGHT_USER = '인원이 부족합니다.',
INVALID_REQUEST = 'invalid_request',
BAD_REQUEST = 'invalid socket request',
}
8 changes: 8 additions & 0 deletions backend/socket/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { RedisIoAdapter } from '@config';

async function bootstrap() {
const app = await NestFactory.create(AppModule);

const redisIoAdapter = new RedisIoAdapter(app);
await redisIoAdapter.connectToRedis();

app.useWebSocketAdapter(redisIoAdapter);

await app.listen(8081);
}

bootstrap();
28 changes: 14 additions & 14 deletions backend/socket/src/room/repository/inmemory-room.repository.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import { ROOM_PHASE } from '@constant';
import { clientId, InmemoryRoom, roomUUID, User, userUUID } from '@types';
import { RoomRepository } from './interface-room.repository';
import { clientId, Room, roomUUID, User, userUUID } from '@types';
import { RoomRepository } from './room.repository';

export class InmemoryRoomRepository implements RoomRepository {
private rooms = new Map<roomUUID, InmemoryRoom>();
private rooms = new Map<roomUUID, Room>();
private usersInRoom = new Map<roomUUID, Set<userUUID>>();
private clientUserIdMap = new Map<clientId, userUUID>();
private userClientIdMap = new Map<userUUID, clientId>();
private userMap = new Map<userUUID, User>();

createRoom({ roomUUID, room }: { roomUUID: string; room: InmemoryRoom }) {
async createRoom({ roomUUID, room }: { roomUUID: string; room: Room }) {
this.rooms.set(roomUUID, room);
this.usersInRoom.set(roomUUID, new Set());
return room;
}

deleteRoom(roomUUID: string) {
async deleteRoom(roomUUID: string) {
this.rooms.delete(roomUUID);
this.usersInRoom.delete(roomUUID);
}

getRoom(roomUUID: string) {
async getRoom(roomUUID: string) {
return this.rooms.get(roomUUID);
}

getUsersInRoom(roomUUID: string) {
async getUsersInRoom(roomUUID: string) {
const userSet = this.usersInRoom.get(roomUUID);
return [...userSet].map((uuid) => this.userMap.get(uuid));
}

saveUserInRoom({
async saveUserInRoom({
clientId,
roomUUID,
user,
Expand All @@ -46,17 +46,17 @@ export class InmemoryRoomRepository implements RoomRepository {
this.userClientIdMap.set(user.uuid, clientId);
}

getUserByClientId(clientId: string) {
async getUserByClientId(clientId: string) {
const uuid = this.clientUserIdMap.get(clientId);
return this.userMap.get(uuid);
}

getClientIdByUser(uuid: string) {
async getClientIdByUser(uuid: string) {
const clientId = this.userClientIdMap.get(uuid);
return clientId;
}

removeUserInRoom({ roomUUID, user }: { roomUUID: string; user: User }) {
async removeUserInRoom({ roomUUID, user }: { roomUUID: string; user: User }) {
const userSet = this.usersInRoom.get(roomUUID);
userSet.delete(user.uuid);

Expand All @@ -67,17 +67,17 @@ export class InmemoryRoomRepository implements RoomRepository {
this.clientUserIdMap.delete(clientId);
}

getRoomPhase(roomUUID: string): ROOM_PHASE {
async getRoomPhase(roomUUID: string) {
const room = this.rooms.get(roomUUID);
return room.phase;
}

updateRoomPhase({ roomUUID, phase }: { roomUUID: string; phase: ROOM_PHASE }) {
async updateRoomPhase({ roomUUID, phase }: { roomUUID: string; phase: ROOM_PHASE }) {
const room = this.rooms.get(roomUUID);
room.phase = phase;
}

updateUserInfo({ uuid, updateUser }: { uuid: string; updateUser: Partial<User> }) {
async updateUserInfo({ uuid, updateUser }: { uuid: string; updateUser: Partial<User> }) {
const user = this.userMap.get(uuid);
for (const key in updateUser) {
user[key] = updateUser[key];
Expand Down
64 changes: 64 additions & 0 deletions backend/socket/src/room/repository/redis-room.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { ROOM_PHASE } from '@constant';
import { InmemoryRoom, User } from '@types';
import { RoomRepository } from './room.repository';
import { pubClient as R } from '@config';

export class RedisRoomRepository implements RoomRepository {
// private rooms = new Map<roomUUID, InmemoryRoom>();
// private usersInRoom = new Map<roomUUID, Set<userUUID>>();
// private clientUserIdMap = new Map<clientId, userUUID>();
// private userClientIdMap = new Map<userUUID, clientId>();
// private userMap = new Map<userUUID, User>();

createRoom({ roomUUID, room }: { roomUUID: string; room: InmemoryRoom }): InmemoryRoom {
throw new Error('Method not implemented.');
}

deleteRoom(roomUUID: string): void {
throw new Error('Method not implemented.');
}

getRoom(roomUUID: string): InmemoryRoom {
throw new Error('Method not implemented.');
}

getUsersInRoom(roomUUID: string): User[] {
throw new Error('Method not implemented.');
}

saveUserInRoom({
clientId,
roomUUID,
user,
}: {
clientId: string;
roomUUID: string;
user: User;
}): void {
throw new Error('Method not implemented.');
}

getUserByClientId(clientId: string): User {
throw new Error('Method not implemented.');
}

getClientIdByUser(uuid: string): string {
throw new Error('Method not implemented.');
}

removeUserInRoom({ roomUUID, user }: { roomUUID: string; user: User }): void {
throw new Error('Method not implemented.');
}

getRoomPhase(roomUUID: string): ROOM_PHASE {
throw new Error('Method not implemented.');
}

updateRoomPhase({ roomUUID, phase }: { roomUUID: string; phase: ROOM_PHASE }): void {
throw new Error('Method not implemented.');
}

updateUserInfo({ uuid, updateUser }: { uuid: string; updateUser: Partial<User> }) {
throw new Error('Method not implemented.');
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { ROOM_PHASE, USER_ROLE } from '@constant';
import { InmemoryRoom, User } from '@types';
import { ROOM_PHASE } from '@constant';
import { Room, User } from '@types';

export interface RoomRepository {
/**
* uuid를 key로 repository에 유저의 socket id를 저장할 객체를 생성하고
* uuid를 key로 방을 식별할 수 있는 객체에 room의 상태를 LOBBY로 저장하는 메서드입니다.
* @param uuid room을 식별할 수 있는 고유한 key
*/
createRoom({ roomUUID, room }: { roomUUID: string; room: InmemoryRoom }): InmemoryRoom;
createRoom({ roomUUID, room }: { roomUUID: string; room: Room }): Promise<Room>;

deleteRoom(roomUUID: string): void;
deleteRoom(roomUUID: string): Promise<void>;

/**
* uuid로 방 정보를 가져옵니다.
* @param roomUUID
* @Return InmemoryRoom
* @Return Room
*/
getRoom(roomUUID: string): InmemoryRoom;
getRoom(roomUUID: string): Promise<Room>;

/**
* room uuid기반으로 해당 방에 존재하는 user 배열을 반환합니다.
* @param roomUUID
* @returns User[]
*/
getUsersInRoom(roomUUID: string): User[];
getUsersInRoom(roomUUID: string): Promise<User[]>;

/**
* room uuid 기반으로 해당 방에 user를 저장합니다.
Expand All @@ -38,37 +38,43 @@ export interface RoomRepository {
clientId: string;
roomUUID: string;
user: User;
}): void;
}): Promise<void>;

/**
* client socket id로 mapping된 user 객체를 반환합니다.
* @param clientId
* @returns User
*/
getUserByClientId(clientId: string): User;
getUserByClientId(clientId: string): Promise<User>;

getClientIdByUser(uuid: string): string;
getClientIdByUser(uuid: string): Promise<string>;

/**
* roomUUID를 기반으로 해당 방에 있는 user를 제거합니다.
* @param clientId socket id
* @param user User
*/
removeUserInRoom({ roomUUID, user }: { roomUUID: string; user: User }): void;
removeUserInRoom({ roomUUID, user }: { roomUUID: string; user: User }): Promise<void>;

/**
* 방의 현재 phase를 반환합니다.
* @param roomUUID
* @returns ROOM_PHASE
*/
getRoomPhase(roomUUID: string): ROOM_PHASE;
getRoomPhase(roomUUID: string): Promise<ROOM_PHASE>;

/**
* 해당 room uuid의 room의 interview phase를 update 합니다.
* @param roomUUID
* @param phase
*/
updateRoomPhase({ roomUUID, phase }: { roomUUID: string; phase: ROOM_PHASE }): void;
updateRoomPhase({ roomUUID, phase }: { roomUUID: string; phase: ROOM_PHASE }): Promise<void>;

updateUserInfo({ uuid, updateUser }: { uuid: string; updateUser: Partial<User> });
updateUserInfo({
uuid,
updateUser,
}: {
uuid: string;
updateUser: Partial<User>;
}): Promise<void>;
}
2 changes: 1 addition & 1 deletion backend/socket/src/room/room.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class RoomGateway implements OnGatewayConnection, OnGatewayDisconnect {

@SubscribeMessage(EVENT.END_FEEDBACK)
handleEndFeedback(@ConnectedSocket() client: Socket) {
return this.interviewService.endFeedback(client);
return this.interviewService.endFeedback({ client, server: this.server });
}

// objectStorage
Expand Down
Loading