채팅방 만들기
채팅 "방"을 만들기 위해서는 각각 개별적인 구분이 필요하다.
입장 해 있는 회원목록이나 회원수가 필요할 것이고, 누가 방장이고, 방 이름이 무엇인지 입력이 필요하다.
직접 room의 Object를 컨트롤 해주는 방법 도 좋지만, Socket.io 에서는 Room 이라는 기능을 제공한다.
단순하게
//채팅방 들어가기
@SubscribeMessage('enterChatRoom')
enterChatRoom(client: Socket, roomId: string) {
client.join(roomId)
}
이런 형태로 client를 room 에 들어갈 수 있다. room은 별도로 생성 할 필요는 없고 단순히 join을 할 경우 room이 생성된다. 마찬가지로 leave 도 별도로 제거 할 필요 없이 해당 room에 아무도 없을 경우 사라진다.
Broadcast로 해당 room에 속해있는 유저에게 모두 발송을 하기위해서는
client.to(roomId).emit('message', message);
이렇게 단순하게 Broadcast가 가능하다.
하지만, 채팅 "방"을 만들기 위해 room 기능을 사용하려고 하는데 몇가지의 내가 구상하는 기능과 맞지 않는점이 몇가지 있었다.
1. room은 1개에만 속하는것이 아닌, 여러개의 room에 속해있을 수 있다.
2. socket이 connect 될 때 기본적으로 해당 소켓 id 이름의 room에 기본적으로 들어가있다.
3. socket에는 data라는 항목에 닉네임 등 custom 데이터를 저장 해 놓을 수 있지만, room은 custom 데이터를 저장 해 놓을만한 마땅한 공간이 별도로 없다.
일단 내가 구상하고있는 채팅방은 1명이 1개의 채팅방에만 속해있는것이고, 처음 접속했을경우, 나가기를 했을 경우 기본으로 로비 채팅방으로 접속하는것이다.
그러나 위 몇가지 맞지 않는 점을 해결해야한다.
일단 1번문제와 3번문제부터 해결해보려 한다.
1. room은 1개에만 속하는것이 아닌, 여러개의 room에 속해있을 수 있다.
3. socket에는 data라는 항목에 닉네임 등 custom 데이터를 저장 해 놓을 수 있지만, room은 custom 데이터를 저장 해 놓을만한 마땅한 공간이 별도로 없다.
이 문제를 해결하기 위해 그리고 좀 더 명확한 Room 관리를 위해 Service.ts로 분리했다.
chatRoom.service.ts
import { Injectable } from '@nestjs/common';
import { chatRoomListDTO } from './dto/chatBackEnd.dto';
import { Socket } from 'socket.io';
import { v4 as uuidv4 } from 'uuid';
@Injectable()
export class ChatRoomService {
private chatRoomList: Record<string, chatRoomListDTO>;
constructor() {
this.chatRoomList = {
'room:lobby': {
roomId: 'room:lobby',
roomName: '로비',
cheifId: null,
},
};
}
createChatRoom(client: Socket, roomName: string): void {
const roomId = `room:${uuidv4()}`;
const nickname: string = client.data.nickname;
this.chatRoomList[roomId] = {
roomId,
cheifId: client.id,
roomName,
};
client.data.roomId = roomId;
client.rooms.clear();
client.join(roomId);
client.emit('getMessage', {
id: null,
nickname: '안내',
message:
'"' + nickname + '"님이 "' + roomName + '"방을 생성하였습니다.',
});
}
enterChatRoom(client: Socket, roomId: string) {
client.data.roomId = roomId;
client.rooms.clear();
client.join(roomId);
const { nickname } = client.data;
const { roomName } = this.getChatRoom(roomId);
client.to(roomId).emit('getMessage', {
id: null,
nickname: '안내',
message: `"${nickname}"님이 "${roomName}"방에 접속하셨습니다.`,
});
}
exitChatRoom(client: Socket, roomId: string) {
client.data.roomId = `room:lobby`;
client.rooms.clear();
client.join(`room:lobby`);
const { nickname } = client.data;
client.to(roomId).emit('getMessage', {
id: null,
nickname: '안내',
message: '"' + nickname + '"님이 방에서 나갔습니다.',
});
}
getChatRoom(roomId: string): chatRoomListDTO {
return this.chatRoomList[roomId];
}
getChatRoomList(): Record<string, chatRoomListDTO> {
return this.chatRoomList;
}
deleteChatRoom(roomId: string) {
delete this.chatRoomList[roomId];
}
}
여러개의 room에 들어갈 수 있는 문제는 client.rooms.clear() 을 활용하여 해결하였다.
clear 함수를 통해 속해있는 모든 room을 제거해 줄 수 있어 만에하나 실수마저도 차단하여 오직 하나만의 room에 속할 수 있도록 하였다.
exitChatRoom 함수에는 나가기 했을 경우 기본적으로 room:lobby로 속해지도록 설정하였다.
Custom한 방 정보를 담기위해 this.chatRoomList라는 Object를 생성 해 주었고, 키는 roomId 로 하였다.
기본적으로 room:lobby가 존재하고, 방이 생성될 때 추가를 해주고, 방 삭제시 지워줌으로서 관리한다.
안에 들어가는 정보는
roomId : 방 고유 id / room:아이디 의 형태를 갖는다.
chiefId: 방장 socket id
roomName: 방 제목 / 방 생성할 시 입력받는다.
세가지 항목이 들어가고, DTO 도 만들어 보았다.
dto/chatBackEnd.dto.ts
export class chatRoomListDTO {
roomId: string;
cheifId: string;
roomName: string;
}
이렇게 함수를 정리하는것을 통해 Custom 정보를 저장할 수 있게 되었다.
2번 문제는 간단하게 해결할 수 있었다.
2. socket이 connect 될 때 기본적으로 해당 소켓 id 이름의 room에 기본적으로 들어가있다.
gateway.ts
//소켓 연결시 유저목록에 추가
public handleConnection(client: Socket): void {
console.log('connected', client.id);
client.leave(client.id);
client.data.roomId = `room:lobby`;
client.join('room:lobby');
}
handleConnection 함수에서 해결을 하였는데, connection이 이루어지자마자 본인 socket id의 room에서 나오고,(client.rooms.clear()을 활용해도 된다.) 기본 채팅방인 'room:lobby'로 들어간다.
이렇게 단순하면서 명확한 채팅방을 제작해 보았다.
'Javascript' 카테고리의 다른 글
블록스코프, 함수스코프 란(feat. var, const, let) (0) | 2021.08.09 |
---|---|
NestJS + Websocket으로 채팅만들기 #4 (feat. 채팅 구색갖추기) (0) | 2021.07.26 |
NestJS + Websocket으로 채팅만들기 #2 (feat. Socket.io) (1) | 2021.07.25 |
Prisma의 단점 - Timezone, 다른ORM은? (2) | 2021.07.23 |
NestJS + Websocket으로 채팅만들기 #1 (1) | 2021.07.16 |
댓글