HwiYul-G / java-chat

spring boot와 react 채팅 - 비속어 탐지 기능이 들어간 웹소켓 채팅 서비스
MIT License
0 stars 0 forks source link

[front] 최초로 들어간 채팅방이 아닐 때 메시지가 보이지 않는 문제 #12

Closed HwiYul-G closed 1 month ago

HwiYul-G commented 2 months ago

문제 상황

  1. 최초로 들어간 채팅방이 아닐 때 메시지가 보이지 않는 문제
    • 사용자 a, b가 존재한다고 하자.
    • a가 그룹 채팅방1(/group/1)에서 대화를 진행한다.
    • 이후 a가 개인 채팅방1(/personal/1)에서 대화를 진행한다.
    • 다시 a가 그룹 채팅방(/group/1)에서 대화를 진행한다.
    • 이때 a가 그룹 채팅방 1로 다시 가서 메시지를 보낼 때 그 메시지는 서버에 명확하게 전달되고 DB에 저장된다.
    • 그러나 a가 보고 있는 화면에서 자신이 보낸 메시지가 보이지 않는 문제가 있다.

관련 코드

import * as StompJs from '@stomp/stompjs';
const client = new StompJs.Client({
    brokerURL: 'ws://localhost:8080/java-chat',
    connectHeaders: {
        Authorization: `Bearer ${localStorage.getItem('token')}`
    },
    debug: function (str){
        // console.log(str);
    },
    reconnectDelay: 5000,
    heartbeatIncoming: 4000,
    heartbeatOutgoing: 4000,
});
client.onConnect = function (frame) {
    console.log("Connected!");
    if (client.subscriptionRequests) {
        client.subscriptionRequests.forEach(sub => {
            client.subscribe(sub.destination, sub.callback);
        });
        client.subscriptionRequests = [];
    }
};
client.onStompError = function(frame){
    console.log('Broker reported error: ' + frame.headers['message']);
    console.log('Additional details: ' + frame.body);
};
const activateClient = () => {
    if(!client.active)
        client.activate();
};
const deactivateClient = () => {
    if(client.active)
        client.deactivate();
};
const sendGroupMessage = (roomId, message) => {
    client.publish({
        destination: `/pub/group-chat-rooms/${roomId}`,
        body: JSON.stringify(message),
        headers: {
            'content-type': 'application/json',
            Authorization: `Bearer ${localStorage.getItem('token')}`
        }
    });
};
const sendPersonalMessage = (roomId, message) =>{
    client.publish({
        destination: `/pub/personal-chat-rooms/${roomId}`,
        body: JSON.stringify(message),
        headers: {
            'content-type': 'application/json',
            Authorization: `Bearer ${localStorage.getItem('token')}`
        }
    });
}
const subscribedGroupRooms = new Set();
const subscribedPersonalRooms = new Set();
const subscribeToGroupRoom = (roomId, callback) => {
    const destination = `/sub/group-chat-rooms/${roomId}`;
    if(subscribedGroupRooms.has(roomId))
        return;
    subscribedGroupRooms.add(roomId);
    if (client.connected) {
        client.subscribe(destination, msg => {
            callback(msg);
        });
    } else {
        if (!client.subscriptionRequests) {
            client.subscriptionRequests = [];
        }
        client.subscriptionRequests.push({ destination, callback });
    }
};
const subscribeToPersonalRoom = (roomId, callback) => {
    const destination = `/sub/personal-chat-rooms/${roomId}`;
    if(subscribedPersonalRooms.has(roomId))
        return;
    subscribedPersonalRooms.add(roomId);
    if (client.connected) {
        client.subscribe(destination, msg => {
            callback(msg);
        });
    } else {
        if (!client.subscriptionRequests) {
            client.subscriptionRequests = [];
        }
        client.subscriptionRequests.push({ destination, callback });
    }
};

const unsubscribeFromGroupRoom = (roomId) => {
    const destination = `/sub/group-chat-rooms/${roomId}`;
    if (subscribedGroupRooms.has(roomId)) {
        client.unsubscribe(destination);
        subscribedGroupRooms.delete(roomId);
    }
};

const unsubscribeFromPersonalRoom = (roomId) => {
    const destination = `/sub/personal-chat-rooms/${roomId}`;

    if (subscribedPersonalRooms.has(roomId)) {
        client.unsubscribe(destination);
        subscribedPersonalRooms.delete(roomId);
    }
};
...
...
const GroupMessagePage = ({roomName}) => {
  ...
  const subscriptionRef = useRef(null);
  const prevRoomIdRef = useRef(params.roomId); // 이전 채팅방 ID

  useEffect(() => {
    ...
    activateClient();

    if(subscriptionRef.current){
      unsubscribeFromGroupRoom(prevRoomIdRef.current);
      subscriptionRef.current.unsubscribe();
    }

    subscriptionRef.current = subscribeToGroupRoom(params.roomId, msg => {
      setAllGroupMessages(prev => [...prev, JSON.parse(msg.body)]);
    });
    ...

    prevRoomIdRef.current = params.roomId;

    return () => {
      if(subscriptionRef.current){
        unsubscribeFromGroupRoom(prevRoomIdRef.current);
        subscriptionRef.current.unsubscribe();
      }
    };
  }, [params.roomId]);
  ...};
...
const PersonalMessagepage = () => {
    ...
    const prevRoomIdRef = useRef(params.roomId); // 이전 채팅방 ID로 활용됨
    useEffect(() => {
        ...
        if(subscriptionRef.current){
              unsubscribeFromPersonalRoom(prevRoomIdRef.current);
              subscriptionRef.current.unsubscribe();
         }

         subscriptionRef.current = subscribeToPersonalRoom(params.roomId, msg => {
            setAllPersonalMessages(prev => [...prev, JSON.parse(msg.body)]);
          });
        ...
        prevRoomIdRef.current = params.roomId;

    return () => {
      if(subscriptionRef.current){
        unsubscribeFromPersonalRoom(prevRoomIdRef.current);
        subscriptionRef.current.unsubscribe();
      }
    };
    });
};

예상 원인

현재 GroupChatRoom Id와 PersonalChatRoom Id가 동일한 점이 문제로 작용되는 것 같다. 두 방의 roomId가 동일한 점이 문제되어, 두 번째로 들어가면서 기존에 한 구독이 해지되고 재구독 되지 않는 문제가 있는 것으로 생각된다.

HwiYul-G commented 2 months ago

해결 방안

각 방에서 stomp를 사용하도록 통합시키면서 pub, sub이 겹치지 않도록 하는 방식 말 그대로 stomp를 각 방 코드에 이식시킨다.

관련 커밋

아쉬운 점

현재 프론트는 기본 학습이 부족한 상태로 진행하는 것이라 구현에 급급한 점을 고려해도.. 코드가 많이 지저분하다는 생각이 듦.

HwiYul-G commented 2 months ago

개선 사항

관련 코드 커밋

장점

아쉬운 점