• 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    미해결

코드에 대한 질문이 잇습니다.

23.11.09 00:13 작성 조회수 250

1

강의를 전부 진행한지 시간이 좀 된 상태에서 프로젝트 리팩토링중 이해가 안되는 부분이 있어 질문드립니다.
아래 의문점에 대해 확인과 의견을 부탁드립니다.
작성된 코드는 제로초님의 front / nest-typeorm 에서 가져온 코드입니다.

의문점 : 채팅 데이터 전송에 웹소켓이 역할을 하지 않는것 같다.

 

그렇게 생각한 근거 :

1-1 : useSocket을 이용해서 소켓에 연결하는데
ws-${workspace} 의 message에 onMessage 함수를 연결하고 있다

const Channel = () => {
  const [socket] = useSocket(workspace);
  
  useEffect(() => {
    socket?.on('message', onMessage);
    return () => {
      socket?.off('message', onMessage);
    };
  }, [socket, onMessage]);
}
const useSocket = (workspace?: string): [Socket | undefined, () => void] => {
  const disconnect = useCallback(() => {
    if (workspace && sockets[workspace]) {
      console.log('소켓 연결 끊음');
      sockets[workspace].disconnect();
      delete sockets[workspace];
    }
  }, [workspace]);
  if (!workspace) {
    return [undefined, disconnect];
  }
  if (!sockets[workspace]) {
    sockets[workspace] = io(`${backUrl}/ws-${workspace}`, {
      transports: ['websocket'],
    });
    console.info('create socket', workspace, sockets[workspace]);
    sockets[workspace].on('connect_error', (err) => {
      console.error(err);
      console.log(`connect_error due to ${err.message}`);
    });
  }

  return [sockets[workspace], disconnect];
};

1-2 : 백엔드에서 채팅을 수신받는 createWorkspaceChannelChats는 ws-${url}-${chatWithUser.ChannelId} 의 message에 받아온 채팅을 보내고 있다.

 async createWorkspaceChannelChats(
    url: string,
    name: string,
    content: string,
    myId: number,
  ) {
    const channel = await this.channelsRepository
      .createQueryBuilder('channel')
      .innerJoin('channel.Workspace', 'workspace', 'workspace.url = :url', {
        url,
      })
      .where('channel.name = :name', { name })
      .getOne();
    const chats = new ChannelChats();
    chats.content = content;
    chats.UserId = myId;
    chats.ChannelId = channel.id;
    const savedChat = await this.channelChatsRepository.save(chats);
    const chatWithUser = await this.channelChatsRepository.findOne({
      where: { id: savedChat.id },
      relations: ['User', 'Channel'],
    });
    this.eventsGateway.server
      // .of(`/ws-${url}`)
      .to(`/ws-${url}-${chatWithUser.ChannelId}`)
      .emit('message', chatWithUser);
  }

 

2 : 네트워크 탭의 웹소켓 메시지에 채팅내역 수신내역이 남지 않는다
이미지가 보일지는 모르겟지만 빨간 박스가 새로 전송한 채팅이고 정상적으로 수신받으면 네트워크 탭에 messag에 내역이 남아야 하는걸로 알고 있는데 남지 않는걸로 확인됩니다.


3 : 웹페이지에서 포커스를 유지한 상태로 모바일에서 입력시 채팅이 전송되지 않음

  • 왜 채팅이 정상적으로 전송된거 처럼 보일까 생각해보니 swr이 브라우저를 포커스 아웃후 재 포커스하면 채팅데이터를 다시 가져오는걸로 추측하여 웹페이지 포커스 유지중 모바일로 테스트해보니 채팅이 전송되지 않습니다.

답변 1

답변을 작성해보세요.

0

제가 강의에서

ws-${url}-${chatWithUser.ChannelId}

여기 구독하는 걸 안 했나보네요.

원래는 swr이랑 웹소켓이랑 둘 다 받아야합니다.

useSocket에서 워크스페이스-채널을 workspace로 전달하면 될 것 같습니다.

최석우님의 프로필

최석우

질문자

2023.11.09

추가적인 확인을 해본결과
제가 안되는 이유와 제로초님의 sleact.nodebird.com 에서 안되는 이유는 다른 이유로 되지 않은거 같습니다.

일단 룸에 대한 구독은 워크스페이스에서 login을 전송시 백단에서 모든 채널의 룸에 가입을 하고 있는것으로 확인됩니다.

  useEffect(() => {
    if (channelData && userData) {
      console.info('로그인하자', socket);
      socket?.emit('login', { id: userData?.id, channels: channelData.map((v) => v.id) });
    }
  }, [socket, userData, channelData]);
@SubscribeMessage('login')
  handleLogin(
    @MessageBody() data: { id: number; channels: number[] },
    @ConnectedSocket() socket: Socket,
  ) {
    const newNamespace = socket.nsp;
    console.log('login', newNamespace);
    onlineMap[socket.nsp.name][socket.id] = data.id;
    newNamespace.emit('onlineList', Object.values(onlineMap[socket.nsp.name]));
    data.channels.forEach((channel) => {
      console.log('join', socket.nsp.name, channel);
      socket.join(`${socket.nsp.name}-${channel}`);
    });
  }

하지만 sleact.nodebird.com 에서 네트워크 탭을 확인해보면 소켓에서 login과 channelId 리스트를 전송하는 내역이 없어 구독이 되지 않은것으로 확인됩니다.
코드상에는 문제가 없어보이나 서비스 중인 코드에서 문제가 있을수 있어 보입니다.

  useEffect(() => {
    if (channelData && userData) {
      console.info('로그인하자', socket);
      socket?.emit('login', { id: userData?.id, channels: channelData.map((v) => v.id) });
    }
  }, [socket, userData, channelData]);

image
추가로 워크스페이스에 모든 채널에 join을 하고 있어 해당부분은 백단에 룸에 join하는 코드를 추가하고 channel이 바뀔때마다 해당 룸에 join 하는것으로 수정이 필요해 보입니다.
다른 채널에서 온 메시지도 해당 채널에 해당하는 room에는 가입되어 있어 message 이벤트가 실행 됩니다.

이게 모든 채널에 조인 하는 것은 다른 채널에서 온 메시지도 받아야하기 때문입니다. 그래야 다른 채널에도 숫자가 올라가고요.

지금 socket.emit('login') 시점에 socket 연결이 없는건 아닌지, 그래서 안 보내지는 건지 생각해봐야겠네요

최석우님의 프로필

최석우

질문자

2023.11.09

읽지않은 메시지수를 가져오려면 모든 룸에 조인해야하는것이 맞네요!

아래 내용은 이전에 작업내용을 깃을 잘못 건드려 날려먹어서 sleact 깃허브 코드를 참고한것으로 실제로는 정상적으로 되어 있으면 문제없습니다.
한번 문제점이 눈에 띄니깐 관련 이슈들이 좀 연달아 보이는거 같네요...

front 폴더의 ChatList, DMList 에서는 EachChannel, EachDm에서 swr에 의해서만 읽지않은 메시지수를 카운트 중이고
front-js 폴더의 ChatList, DMList 에서는 swr을 사용하지않고 웹소켓을 구독한것으로 읽지않은 메시지 수를 가져오있네요