import { Injectable, OnModuleInit } from '@nestjs/common' import { debug, Debugger } from 'debug' import { chunk, isEmpty, isNil } from 'lodash' import { nanoid } from 'nanoid' import { Firebender } from '../firebender' import { PushPayload } from './value-objects' export const DEVICES_CHUNK_LIMIT = 800 export const FLUTTER_CLICK_ACTION = 'FLUTTER_NOTIFICATION_CLICK' export type PushNotificationTemplate = { title: string; message: string; page: string } @Injectable() export class MessagingService implements OnModuleInit { private debug: Debugger = debug(`http:${this.constructor.name}`) private firebender: Firebender onModuleInit(): void { this.firebender = new Firebender() } async sendPushNotificationByTemplate( { title, message, page }: PushNotificationTemplate, deviceId: string, ): Promise { const push: PushPayload = PushPayload.toInstance({ notification: { title, body: message, }, data: { click_action: FLUTTER_CLICK_ACTION, page, }, }) await this.sendPushNotification(deviceId, push) } async sendPushNotification(devices: string | Array, payload: PushPayload): Promise { if (isNil(devices) || isEmpty(devices) || isNil(payload)) return null if (Array.isArray(devices)) { const chunked = chunk(devices, DEVICES_CHUNK_LIMIT) for (const chunkDevices of chunked) { try { await this.push(payload, chunkDevices) } catch (err) { this.debug(`Error sending Push Notification '${payload?.notification?.title}': ${err.messages}`) } } return null } try { await this.push(payload, devices) } catch (err) { this.debug(`Error sending Push Notification '${payload?.notification?.title}': ${err.messages}`) } } private push = async (payload: PushPayload, devices: string | Array): Promise => { const id = nanoid() this.debug.extend('request')(JSON.stringify({ id, type: 'push', body: { ...payload, devices } })) const response = await this.firebender.firebaseAdmin.messaging().sendToDevice(devices, { ...JSON.parse(JSON.stringify(payload)), }) this.debug.extend('response')(JSON.stringify({ id, response })) } }