From 0724a122248177430dd53a944aa0796fda36c943 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:36:27 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20fcm=20=EC=B1=84=ED=8C=85=20=ED=91=B8?= =?UTF-8?q?=EC=8B=9C=20=EC=95=8C=EB=A6=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wsServer.js | 108 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 18 deletions(-) diff --git a/wsServer.js b/wsServer.js index 3f303b5..12ef05a 100644 --- a/wsServer.js +++ b/wsServer.js @@ -2,8 +2,21 @@ const http = require('http'); const crypto = require('crypto'); // const ChatRoom = require('./models/chatRoom.js'); const mongoose = require('mongoose'); +const admin = require('firebase-admin'); +const dotenv = require('dotenv'); const ChatRoom = require('./models/chatRooms'); +// .env 파일 로드 +dotenv.config(); + +// 서비스 계정 키 파일 경로를 환경 변수에서 가져오기 +const serviceAccountPath = process.env.FIREBASE_CREDENTIAL_PATH; + +// Firebase Admin SDK 초기화 +admin.initializeApp({ + credential: admin.credential.cert(require(serviceAccountPath)), +}); + // WebSocket 관련 데이터 let clients = []; let chatRooms = {}; @@ -85,8 +98,6 @@ function startWebSocketServer() { if (type === 'join') { chatRoomId = clientChatRoomId; nickname = clientNickname; - console.log("join시 chatRoomId", chatRoomId); - console.log("join시 nickname", nickname); await ChatRoom.updateOne( { chatRoomId }, @@ -103,32 +114,42 @@ function startWebSocketServer() { } const chatRoom = await ChatRoom.findOne({ chatRoomId }); - console.log("join시 chatRoom", chatRoom); - if (!chatRoom) { - console.error(`ChatRoom을 찾을 수 없습니다: chatRoomId = ${chatRoomId}`); - } else { - console.log(`ChatRoom 조회 성공: ${chatRoom}`); - } - const isAlreadyParticipant = chatRoom.participants.includes(nickname); - if (!isAlreadyParticipant) { + // 참가자 확인 + const participantIndex = chatRoom.participants.findIndex(participant => participant.name === nickname); + if (participantIndex !== -1) { + const existingParticipant = chatRoom.participants[participantIndex]; + + // 참가자 상태 업데이트 + existingParticipant.isOnline = true; + existingParticipant.lastReadAt = new Date(); + + await chatRoom.save(); + } else { + // 새 참가자 추가 const joinMessage = { message: `${nickname}님이 참가했습니다.`, timestamp: new Date(), type: 'join' }; - chatRooms[chatRoomId].push(joinMessage); - - await ChatRoom.updateOne({ chatRoomId }, { - $push: { messages: joinMessage, participants: nickname } + chatRoom.participants.push({ + name: nickname, + fcmTokens: parsedData.fcmToken ? [parsedData.fcmToken] : [], + lastReadAt: new Date(), + lastReadLogId: null, + isOnline: true, }); + chatRoom.messages.push(joinMessage); + + await chatRoom.save(); + clients.forEach(client => { client.write(constructReply(JSON.stringify(joinMessage))); }); - } else { - console.log(`${nickname}은 이미 채팅방에 참가 중입니다.`); + + console.log(`${nickname} 새 참가자로 추가`); } try { @@ -177,12 +198,63 @@ function startWebSocketServer() { client.write(constructReply(JSON.stringify(messageData))); console.log('채팅 메시지 전송:', messageData); }); - + + // 오프라인 사용자에게 FCM 푸시 알림 전송 + const chatRoom = await ChatRoom.findOne({ chatRoomId }); + const offlineParticipants = chatRoom.participants.filter(participant => { + // isOnline 상태를 Map에서 가져오기 + const isOnline = chatRoom.isOnline.get(participant.name); + return isOnline === false; // 정확히 false인 사용자만 필터링 + }); + + + for (const participant of offlineParticipants) { + const tokens = participant.fcmTokens || []; + // console("푸시 알림 보내는 토큰", tokens); + if (tokens.length > 0) { + const message = { + tokens, // FCM 토큰 배열 + notification: { + title: `${chatRoom.chatRoomName}`, + body: `${nickname}: ${text}`, + }, + data: { + key1: 'value1', + key2: 'value2', + }, + android: { + priority: 'high', + }, + apns: { + payload: { + aps: { + sound: 'default', + }, + }, + }, + }; + + try { + console.log(`푸시 알림 전송 중 (${participant.name}):`, message); // 디버깅 로그 추가 + const response = await admin.messaging().sendEachForMulticast(message); + console.log(`푸시 알림 전송 성공 (${participant.name}):`, response.successCount); + } catch (error) { + console.error(`푸시 알림 전송 실패 (${participant.name}):`, error); + } + } else { + console.log(`사용자 ${participant.name}의 FCM 토큰이 없습니다.`); + } + } } catch (err) { console.error('MongoDB 채팅 메시지 저장 오류:', err); } } else if (type === 'leave') { - const leaveMessage = { message: `${nickname}님이 퇴장했습니다.`, timestamp: new Date() }; + const leaveMessage = { + message: `${nickname}님이 퇴장했습니다.`, + timestamp: new Date(), + type: 'leave' + }; + chatRooms[chatRoomId].push(leaveMessage); await ChatRoom.updateOne( -- GitLab