Project/SeSAC 3차 팀 프로젝트

3차 팀 프로젝트 리팩토링 #2 (채팅방 입/퇴장 메시지)

다니니니 2024. 11. 20. 01:06
728x90

 

들어가며

 

리팩토링 하기 전의 채팅방 기능에는 누군가가 모임에 들어갔을 때, 즉 채팅방에 입장했을 때 입장했다는 메시지가 없었다.

이런식으로 누군가가 들어왔음에도 어떤 사람이 입장했는 지에 대한 메시지가 없었다.

사용자 경험을 개선하기 위해 입/퇴장 메시지를 표시하는 것으로 리팩토링을 했다.

 

리팩토링 과정

 

이 프로젝트에서는 특정 모임을 생성하면 그 모임에 대한 채팅방이 열리고,

누군가가 모임을 가입했을 때 채팅방에 입장하는 구조였다.

 

그러므로 입/퇴장 메시지를 받기 위해서는 누군가가 모임을 가입/탈퇴 했다는 정보가 필요했다.

즉, 사용자가 보내는 메시지가 아니라 일종의 시스템? 메시지를 받아 올 수 있도록 서버에서부터 코드를 고쳐야 했다.

담당 백엔드 분과 대화해서 그렇게 할 수 있도록 서버 쪽 코드를 고쳤다.

 

고친 후에 확인을 하는데

입/퇴장 메시지가 실시간으로 오지 않고 새로고침을 하면 반영이 되었다.

즉, DB 에서 불러오는 것 자체는 문제가 없는데 websocket 에서의 설정이 잘못된 것 같았다.

 

STOMP.js 를 이용한 웹 소켓 코드에서 subscribe 메서드 내에서 메시지를 받는다.

메시지는 mesage.body 내에 담겨서 온다.

// 클라이언트 초기화
    clientRef.current = new Client({
      webSocketFactory: () => new SockJS(`${url}/ws`),
      // 생략
      onConnect: () => {
        // 모든 채팅방에 대해 구독
        chatroomIds.forEach((chatroomId) => {
          if (!subscriptionsRef.current.has(chatroomId)) {
            const chatTopic = `/topic/chatroom/${chatroomId}`;
            const subscription = clientRef.current?.subscribe(
              chatTopic,
              (message) => {
                console.log(JSON.parse(message.body));
				// 생략
            }
          });
        });
      },

 

그런데 서버에서 받아오는 시스템 메시지와 일반 채팅 메시지가 오는 구조가 달랐다.

 

시스템 메시지
일반 채팅 메시지

위의 캡처를 보면 일반 채팅 메시지는 body 안에 data 안에 필요한 정보가 있는 반면

시스템 메시지는 바로 오는 구조였다.

 

처음에는 데이터를 오는 형태를 통일 시켜달라고 했지만

굳이 서버 코드를 건드리지 않고 프론트 내에서 할 수 있을 것 같았다.

 

// 클라이언트 초기화
    clientRef.current = new Client({
      webSocketFactory: () => new SockJS(`${url}/ws`),
      // 생략
      onConnect: () => {
        // 모든 채팅방에 대해 구독
        chatroomIds.forEach((chatroomId) => {
          if (!subscriptionsRef.current.has(chatroomId)) {
            const chatTopic = `/topic/chatroom/${chatroomId}`;
            const subscription = clientRef.current?.subscribe(
              chatTopic,
              (message) => {
                const chatMessage = JSON.parse(message.body).body.data
                
                dispatch(setMessages([...messages, chatMessage]))
            }
          });
        });
      },

 

기존 코드는 위와 같이 

JSON.parse(message.body).body.data 이것을 chatMessage 변수에 담아서

redux dispatch action 을 이용해 message 배열에 담았다.

그러다보니 구조가 맞지 않아 시스템 메시지가 실시간으로 보여지지 않았던 것이다.

// 클라이언트 초기화
    clientRef.current = new Client({
      webSocketFactory: () => new SockJS(`${url}/ws`),
      // 생략
      onConnect: () => {
        // 모든 채팅방에 대해 구독
        chatroomIds.forEach((chatroomId) => {
          if (!subscriptionsRef.current.has(chatroomId)) {
            const chatTopic = `/topic/chatroom/${chatroomId}`;
            const subscription = clientRef.current?.subscribe(
              chatTopic,
              (message) => {
                const chatMessage =JSON.parse(message.body).headers
                  ? JSON.parse(message.body).body.data
                  : JSON.parse(message.body);
                
                dispatch(setMessages([...messages, chatMessage]))
            }
          });
        });
      },

 

그래서 위와 같이 바꿨다.

삼항연산자를 이용해서 JSON.parse(message.body) 로 오는 형태의 데이터가 headers 속성을 가지고 있는지 확인했다.

그래서 있다면 JSON(message.body).body.data 의 데이터를 변수에 담고 아니라면 JSON.parse(message.body) 의 데이터를 담았다.

 

결과

 

 

위의 그림과 같이 실시간으로 시스템메시지(입/퇴장 메시지) 를 구현할 수 있었다.

 

발표 때 이것을 표현했다면 더 좋았겠다는 아쉬움이 남았지만.

그래도 리팩토링을 함으로써 조금의 사소한 표현으로 프로젝트의 완성도를 조금이라도 높일 수 있어서 좋았다.

728x90