TIL 83일차 (20240424)

박세연·2024년 4월 24일

TIL

목록 보기
69/70


오늘 한 일

  • db에서 dmRoomId에 해당하는 채팅 내역들 불러오기
  • 채팅 버그 수정

1. 채팅 버그 수정

오늘 일어난 채팅 에러는 한 dmroom에서 보낸 메세지가 다른 dmroom에 보내지는 에러였다. 시간을 많이 소요했던 이유는 이 에러가 처음부터 일어난게 아니라 한 5~6번은 정상적으로 특정 방에만 보내지다가 갑자기 다른 방에도 보내지던 에러라 이유를 발견하기 어려웠기 때문이다. 그래서 다른 코드를 참고 삼아 gateway를 많이 수정했다.
참고한 블로그 주소: https://kigo23.tistory.com/23

///event.gateway.ts

@WebSocketGateway({ namespace: ~~~~ })
export class DMGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer()
  server: Server;

  constructor(
    private readonly dmService: DMService,
    private readonly userService: UserService,
    private readonly jwtService: JwtService,
    private readonly config: ConfigService,
  ) {}

  connectedClients: { [socketId: string]: boolean } = {};
  clientNickname: { [socketId: string]: string } = {};
  roomUsers: { [key: string]: string[] } = {};

  async handleConnection(@ConnectedSocket() socket: Socket) {
    if (this.connectedClients[this.clientNickname.id]) {
      socket.disconnect(true);
      return;
    }

    this.connectedClients[socket.id] = true;

    const cookie = socket.handshake.headers.cookie;
    const user = await this.findUserByCookie(cookie);

    this.clientNickname[socket.id] = user.nickname;

    console.log('dm connected!');
  }

  async findUserByCookie(cookie: string) {
    // const cookie = socket.handshake.headers.cookie; 로 미리 받아와야함

    const token = cookie.split('=')[1];
    const payload = this.jwtService.verify(token, { secret: this.config.get<string>('JWT_SECRET_KEY') });
    const user = await this.userService.findUserByEmail(payload.email);

    return user;
  }

  async handleDisconnect(@ConnectedSocket() client: Socket) {
    delete this.connectedClients[client.id];
    const cookie = client.handshake.headers.cookie;
    const user = await this.findUserByCookie(cookie);

    Object.keys(this.roomUsers).forEach(room => {
      const index = this.roomUsers[room]?.indexOf(this.clientNickname[client.id]);

      if (index !== -1) {
        this.roomUsers[room].splice(index, 1);
      }
    });
  }

  @SubscribeMessage('sayBye')
  async leaveDMRoom(@ConnectedSocket() socket: Socket, @MessageBody() dmRoomId: string) {
    if (!socket.rooms.has(dmRoomId)) {
      return;
    }

    socket.leave(dmRoomId);

    const index = this.roomUsers[dmRoomId]?.indexOf(this.clientNickname[socket.id]);
    if (index !== -1) {
      this.roomUsers[dmRoomId].splice(index, 1);
      this.server.to(dmRoomId).emit('bye', { nickname: this.clientNickname[socket.id], dmRoomId });
    }

    const cookie = socket.handshake.headers.cookie;
    const user = await this.findUserByCookie(cookie);

    this.server.to(dmRoomId).emit('bye', { nickname: this.clientNickname[socket.id], dmRoomId });
  }

  @SubscribeMessage('joinDM')
  async handleJoinDM(@ConnectedSocket() socket: Socket, @MessageBody() dmRoomId: any) {
    if (socket.rooms.has(dmRoomId)) {
      return;
    }
    const cookie = socket.handshake.headers.cookie;
    const user = await this.findUserByCookie(cookie);

    socket.join(dmRoomId);
    console.log(`${user.nickname}의 벡엔드는 여기에 연결 중: ${dmRoomId}`);

    if (!this.roomUsers[dmRoomId]) {
      this.roomUsers[dmRoomId] = [];
    }

    this.roomUsers[dmRoomId].push(this.clientNickname[socket.id]);

    this.server.to(dmRoomId).emit('welcome', { nickname: this.clientNickname[socket.id], dmRoomId });
  }

  @SubscribeMessage('sendMessage')
  async handleMessage(@MessageBody() data, @ConnectedSocket() socket: Socket) {
    const cookie = socket.handshake.headers.cookie;
    const user = await this.findUserByCookie(cookie);

    const userId = user.id;
    const nickname = user.nickname;
    const content = data.value;
    const dmRoomId = +data.dmRoomId;

    await this.dmService.saveDM(dmRoomId, userId, content);

    socket.join(data.dmRoomId);
    console.log('socket 백엔드: ', data.dmRoomId);

    const time = new Date();

    this.server.to(data.dmRoomId).emit('message', { dmRoomId, nickname, content, time });
  }

  @SubscribeMessage('dmRoomList')
  async dmRoomList(socket: Socket) {
    const cookie = socket.handshake.headers.cookie;
    const user = await this.findUserByCookie(cookie);
    const userId = user.id;

    const dmRooms = await this.dmService.getDMRooms(user.id);

    const promiseDmRoomIds = dmRooms.map(async e => {
      const id = e.dmRoom_id;
      const nickname1 = e.fr_nickname;
      const nickname2 = e.us_nickname;
      const userNickname = user.nickname;

      if (userNickname === nickname1) {
        return { id, nickname: nickname2 };
      } else if (userNickname === nickname2) {
        return { id, nickname: nickname1 };
      }
    });

    const dmRoomIds = await Promise.all(promiseDmRoomIds);

    socket.emit('rooms', dmRoomIds);
  }
}

nickname과 socket의 이름을 따로 받았다. 그리고 data가 disconnect될 때 socket.leave(dmRoomId);을 추가했는데 아마 이 부분이 없었기에 지난번에 그 에러가 나지 않았을까 싶다.


이전 채팅 내역 불러오기

원래 계획은 gateway에서 dmService를 불러와 가져오는 것이었다. 그런데 튜터님의 조언으로 프론트에서 api를 호출하여 불러오는 것으로 변경했다. 다행히 어제 fetch를 많이 작성해서 오래 걸리지는 않았다. fetch만 ㅋ... 이걸 화면에 보내주고 새 채팅까지 합치는 것이 더 많이 걸렸다.

// api 호출하고 출력까지 하는 프론트 함수

fetch(`http://localhost:3000/dm/history/${dmRoomId}`,{
  headers:{
    Authorization:`Bearer ${token}`
}
})
.then(res=>res.json())
.then(data=>data.map(chat=>{
  sendDM(`${chat.us_nickname}:${chat.chat_content} ${chat.chat_created_at}`)
}))
.catch(err=> console.error('채팅 내역 가져오는데 오류 발생: ', err));
}
profile
배워나가는 중

0개의 댓글