From 725161468253f2abb763371d433711f5d3641227 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=8B=AC=EC=9E=AC=EC=97=BD?= <jysim0326@ajou.ac.kr>
Date: Mon, 25 Nov 2024 17:38:22 +0900
Subject: [PATCH] =?UTF-8?q?refactor:=20fcm=20=EC=B1=84=ED=8C=85=20?=
 =?UTF-8?q?=ED=91=B8=EC=8B=9C=20=EC=95=8C=EB=A6=BC=20=EC=B6=94=EA=B0=80,?=
 =?UTF-8?q?=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=9D=BD=EC=9D=8C=20=EC=88=98?=
 =?UTF-8?q?=20=ED=99=95=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 services/chatService.js | 165 ++++++++++++++++++++++++++++------------
 1 file changed, 115 insertions(+), 50 deletions(-)

diff --git a/services/chatService.js b/services/chatService.js
index 4135d15..c5e3a3c 100644
--- a/services/chatService.js
+++ b/services/chatService.js
@@ -2,58 +2,46 @@ const ChatRoom = require('../models/chatRooms');
 const { v4: uuidv4 } = require('uuid');
 
 class ChatService {
-
   // 채팅방 생성
-  async createChatRoom({ meeting_id, participants }) {
-    try {
-      const chatRoomId = uuidv4();
-      const newRoom = new ChatRoom({
-        chatRoomId: chatRoomId,
-        meeting_id,
-        participants,
-        messages: [],
-        lastReadAt: participants.reduce((acc, user) => {
-          acc[user] = new Date();
-          return acc;
-        }, {}),
-        lastReadLogId: participants.reduce((acc, user) => {
-          acc[user] = null;
-          return acc;
-        }, {}),
-        isOnline: participants.reduce((acc, user) => {
-          acc[user] = true;
-          return acc;
-        }, {}),
-      });
-
-      const joinMessage = {
-        message: `${participants[0]}님이 번개 모임을 생성했습니다.`,
-        timestamp: new Date(),
-        type: 'join',
-      };
+  async createChatRoom({ meeting_id, participants, chatRoomName }) {
+  try {
+    const chatRoomId = uuidv4();
+    const newRoom = new ChatRoom({
+      chatRoomId,
+      chatRoomName,
+      meeting_id,
+      messages: [],
+    });
 
-      newRoom.messages.push(joinMessage);
-      await newRoom.save();
+    const joinMessage = {
+      message: `${participants[0].name}님이 번개 모임을 생성했습니다.`,
+      timestamp: new Date(),
+      type: 'join',
+    };
 
-      return { success: true, chatRoomId };
-    } catch (err) {
-      console.error('Error creating chat room:', err);
-      throw new Error('Failed to create chat room');
-    }
+    newRoom.messages.push(joinMessage);
+    await newRoom.save();
+
+    return { success: true, chatRoomId };
+  } catch (err) {
+    console.error('Error creating chat room:', err);
+    throw new Error('Failed to create chat room');
   }
+}
 
   // 채팅방 목록 조회
   async getChatRooms() {
-    const rooms = await ChatRoom.find({}, { chatRoomId: 1, messages: { $slice: -1 } });
+    const rooms = await ChatRoom.find({}, { chatRoomId: 1, chatRoomName: 1, messages: { $slice: -1 } });
     return rooms.map(room => {
       const lastMessage = room.messages[0] || {};
       return {
         chatRoomId: room.chatRoomId,
+        chatRoomName: room.chatRoomName,
         lastMessage: {
           sender: lastMessage.sender || '없음',
           message: lastMessage.message || '메시지 없음',
           timestamp: lastMessage.timestamp || null,
-        }
+        },
       };
     });
   }
@@ -61,7 +49,7 @@ class ChatService {
   // 사용자 상태 업데이트
   async updateStatus(chatRoomId, nickname, isOnline) {
     await ChatRoom.updateOne(
-      { chatRoomId },
+      { chatRoomId, "participants.name": nickname },
       { $set: { [`isOnline.${nickname}`]: isOnline } }
     );
   }
@@ -70,14 +58,14 @@ class ChatService {
   async updateReadStatus(chatRoomId, nickname) {
     const now = new Date();
     await ChatRoom.updateOne(
-      { chatRoomId },
+      { chatRoomId, "participants.name": nickname },
       { $set: { [`lastReadAt.${nickname}`]: now } }
     );
   }
 
   // 읽지 않은 메시지 조회
   async getUnreadMessages(nickname) {
-    const chatRooms = await ChatRoom.find({ participants: nickname });
+    const chatRooms = await ChatRoom.find({ "participants.name": nickname });
     return await Promise.all(chatRooms.map(async (chatRoom) => {
       const lastReadAt = chatRoom.lastReadAt.get(nickname) || new Date(0);
       const unreadMessagesCount = chatRoom.messages.filter(message => 
@@ -98,31 +86,49 @@ class ChatService {
     }
 
     const unreadCounts = chatRoom.participants
-      .filter(user => chatRoom.lastReadLogId.get(user))
-      .map(user => chatRoom.lastReadLogId.get(user))
+      .filter(participant => chatRoom.lastReadLogId.has(participant.name)) // Map에 존재하는 키만 처리
+      .map(participant => chatRoom.lastReadLogId.get(participant.name)) // lastReadLogId 값 추출
       .reduce((acc, logId) => {
-        acc[logId] = (acc[logId] || 0) + 1;
+        acc[logId] = (acc[logId] || 0) + 1; // logId 기준으로 등장 횟수 누적
         return acc;
       }, {});
 
     let count = 0;
-    return Object.entries(unreadCounts)
-      .sort(([logId1], [logId2]) => logId1.localeCompare(logId2))
+    const sortedUnreadCounts = Object.entries(unreadCounts)
+      .sort(([logId1], [logId2]) => logId1.localeCompare(logId2)) // logId 기준 오름차순 정렬
       .reduce((acc, [logId, value]) => {
-        count += value;
-        acc[count] = logId;
+        count += value; // 누적 합계
+        acc[count] = logId; // 누적 합계를 키로 저장
         return acc;
       }, {});
+
+    return sortedUnreadCounts;
   }
 
   // 읽은 메시지 로그 ID 업데이트
   async updateReadLogId(chatRoomId, nickname, logId) {
     await ChatRoom.updateOne(
-      { chatRoomId },
+      { chatRoomId, "participants.name": nickname },
       { $set: { [`lastReadLogId.${nickname}`]: logId } }
     );
   }
 
+  // FCM 토큰 업데이트
+  async updateFcmToken(chatRoomId, nickname, fcmToken) {
+    const chatRoom = await ChatRoom.findOne({ chatRoomId, "participants.name": nickname });
+    if (!chatRoom) {
+      throw new Error('Chat room or participant not found');
+    }
+
+    const participant = chatRoom.participants.find(p => p.name === nickname);
+    if (participant) {
+      if (!participant.fcmTokens.includes(fcmToken)) {
+        participant.fcmTokens.push(fcmToken);
+        await chatRoom.save();
+      }
+    }
+  }
+
   // 상태와 로그 ID 동시 업데이트
   async updateStatusAndLogId(chatRoomId, nickname, isOnline, logId) {
     let finalLogId = logId;
@@ -135,7 +141,7 @@ class ChatService {
     }
 
     await ChatRoom.updateOne(
-      { chatRoomId },
+      { chatRoomId, "participants.name": nickname },
       {
         $set: {
           [`isOnline.${nickname}`]: isOnline,
@@ -144,6 +150,65 @@ class ChatService {
       }
     );
   }
+
+  // 메시지 전송
+  async sendMessage(chatRoomId, sender, messageContent) {
+    try {
+      // 채팅방 조회
+      const chatRoom = await ChatRoom.findOne({ chatRoomId });
+      if (!chatRoom) {
+        throw new Error('Chat room not found');
+      }
+
+      // 메시지 추가
+      const newMessage = {
+        sender,
+        message: messageContent,
+        timestamp: new Date(),
+        type: 'message',
+      };
+      chatRoom.messages.push(newMessage);
+      await chatRoom.save();
+
+      // 오프라인 사용자 찾기
+      const offlineParticipants = chatRoom.participants.filter(
+        participant => !chatRoom.isOnline[participant.name]
+      );
+
+      // 오프라인 사용자들에게 FCM 푸시 알림 전송
+      for (const participant of offlineParticipants) {
+        const tokens = participant.fcmTokens || [];
+        if (tokens.length > 0) {
+          const message = {
+            notification: {
+              title: `새 메시지: ${chatRoom.chatRoomName}`,
+              body: `${sender}: ${messageContent}`,
+            },
+            tokens,
+          };
+
+          try {
+            const response = await admin.messaging().sendMulticast(message);
+            console.log(
+              `푸시 알림 전송 성공 (${participant.name}):`,
+              response.successCount
+            );
+          } catch (error) {
+            console.error(
+              `푸시 알림 전송 실패 (${participant.name}):`,
+              error
+            );
+          }
+        }
+      }
+
+      return newMessage;
+    } catch (error) {
+      console.error('Error sending message:', error);
+      throw new Error('Failed to send message');
+    }
+  }
+
 }
 
-module.exports = new ChatService();
+module.exports = new ChatService();
\ No newline at end of file
-- 
GitLab