firebase 연동해서 fcm 사용하기이란!
🦥 FCM 사용
fcm 을 처음에는 코프링으로 구현하다가, App Check 가 스프링에서는 구현이 안된다는 이슈로 node 로 다시 구현하기 시작했다.
내가 구현한 기능은 조금 많고 복잡하다. 내가 실력이 부족한건지, 아님 공통으로 줄일 수 있는데, 내가 못줄인것인지,, 이렇게 작성해놓으면 , 미래의 내가 보고 깨달음을 주겠지!
참고로 이게시글에는 백엔드 관련해서만 작성하겠다!
왜냐, node 를 하면서 오랜만에 백엔드 비즈니스 로직을 작성을 했고, 그 흐름을 잊어버리지 않기 위함이다.
- 데이터베이스는 fcm 예약 DB, fcm 히스토리 DB 2개 존재한다.
토큰, 주제 의 전송방식으로 즉시 전송과 예약 전송 두가지 메소드가 존재한다.
즉시전송!
즉시전송은 바로 fcm 이 전송되기때문에, 전송 성공시 히스토리 DB에 남기는 로직으로 진행했다.
// 토큰으로 보내기
public async sendByToken(fcm: FcmModel): Promise<boolean> {
try {
const message = {
notification: {
title: fcm.title ?? '',
body: fcm.content,
},
token: fcm.target,
}
// 즉시 발송인 경우, 히스토리 디비에 저장
return await admin.messaging().send(message)
.then(_ => {
return fcmHistoryService.insertToHistory(fcm, '토큰')
}).catch(err => {
console.error(err);
return false
});
} catch (err) {
console.error('sendBy Token : ', err)
}
}
// 주제(토픽)로 보내기
public async sendByTopic(fcm): Promise<boolean> {
try {
const msg = {
notification: {
title: fcm.title ?? '',
body: fcm.content,
},
topic: fcm.topic!,
}
// 즉시 발송인 경우, 히스토리 디비에 저장
return await admin.messaging().send(msg).then(_ => {
return fcmHistoryService.insertToHistory(fcm, '주제')
}).catch(err => {
console.error(err);
return false
})
} catch (err) {
console.error('sendBy Token : ', err)
}
}
예약 전송
예약전송은 우선 예약 DB 에 등록을 하고 node-cron 을 통해서 정해진 시간에 DB 를 읽어와 예약시간에 맞춰 전송해주는 방식으로 진행했다.
async insertToReservation(fcm: FcmModel, type: String): Promise<boolean> {
const db: Firestore = admin.firestore();
try {
let timeStamp = String(Date.now());
dayjs.extend(utc);
dayjs.extend(timezone);
const randomString = Array.from({length: 5}, () => (Math.random().toString(36)[2].toUpperCase())).join('');
const documentId = `${timeStamp}${randomString}`;
const obj = {
title: fcm.title,
content: fcm.content,
createdAt: fcm.createdAt,
reservationAt: fcm.reservationAt,
docId: documentId,
messageType: type,
target: fcm.target ?? null,
topic: fcm.topic ?? null,
isReservation: fcm.isReservation,
};
const result = await db.collection('reservation').doc(documentId).set(obj)
.then(_ => {
return true;
}).catch(err => {
console.error(err);
return false;
});
return result;
} catch (err) {
console.error(err);
}
}
cron_utils 코드
index.ts 에 require() 해주었다.
import Timestamp = firestore.Timestamp;
const cron = require('node-cron');
const fcmReservationService = new FcmReservationService();
const task = cron.schedule('*/30 * * * *', async function () {
try {
let reservationList: FcmModel[] = [];
const timeStamp = Timestamp.now();
const result = await fcmReservationService.lists(null, null);
if (result) {
result.map((e) => {
if (e.reservationAt?.seconds == timeStamp.seconds) {
reservationList.push(e);
}
})
reservationList.map(async (tempElement) => {
if (tempElement.messageType === '토큰') {
await fcmReservationService.sendByToken(tempElement).then(async _ => {
// 예약 서비스에서 삭제!
await fcmReservationService.deleteReservation(tempElement.docId);
});
} else {
await fcmReservationService.sendByTopic(tempElement).then(async _ => {
// 예약 서비스에서 삭제!
await fcmReservationService.deleteReservation(tempElement.docId);
});
}
})
}
} catch (err) {
console.error(err);
} finally {
reservationList = [];
}
}, {
scheduled: true
})
module.exports = task;
Leave a comment