UNPKG

firebase-fcm-v1-http2

Version:

A Node.js library for sending push notifications using Firebase Cloud Messaging HTTP v1 APIs.

105 lines (104 loc) 4.42 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.processBatch = processBatch; const http2 = __importStar(require("http2")); const async = __importStar(require("async")); const fcmv1Api = 'https://fcm.googleapis.com'; function processBatch(message, devices, projectId, accessToken, maxConcurrentStreamsAllowed, maxConcurrentConnections) { return new Promise((resolve, reject) => { const client = http2.connect(fcmv1Api, { peerMaxConcurrentStreams: maxConcurrentConnections }); client.on('error', (err) => reject(err)); client.on('socketError', (err) => reject(err)); client.unregisteredTokens = []; async.eachLimit(devices, maxConcurrentStreamsAllowed, (device, doneCallback) => { sendRequest(client, device, message, projectId, accessToken, doneCallback, 0, maxConcurrentStreamsAllowed, maxConcurrentConnections); }, (err) => { client.close(); if (err) return reject(err); resolve(client.unregisteredTokens); }); }); } function sendRequest(client, device, message, projectId, accessToken, doneCallback, tries, maxConcurrentStreamsAllowed, maxConcurrentConnections) { const request = client.request({ ':method': 'POST', ':scheme': 'https', ':path': `/v1/projects/${projectId}/messages:send`, Authorization: `Bearer ${accessToken}`, }); request.setEncoding('utf8'); const clonedMessage = Object.assign(Object.assign({}, message), { token: device }); request.write(JSON.stringify({ message: clonedMessage })); let data = ''; request.on('data', (chunk) => { data += chunk; }); let retrying = false; const errorHandler = (err) => { if (tries <= 3) { if (retrying) return; retrying = true; if (client.destroyed) { return processBatch(message, [device], projectId, accessToken, maxConcurrentStreamsAllowed, maxConcurrentConnections) .finally(doneCallback); } return setTimeout(() => sendRequest(client, device, message, projectId, accessToken, doneCallback, tries + 1, maxConcurrentStreamsAllowed, maxConcurrentConnections), 10000); } err.data = data; doneCallback(err); }; request.on('end', () => { var _a; try { if (data.toLowerCase().includes('server error')) { return errorHandler(new Error('Internal Server Error')); } const response = JSON.parse(data); const statusCode = (_a = response.statusCode) !== null && _a !== void 0 ? _a : response.status; if (statusCode && statusCode >= 500) { return errorHandler(new Error(`${statusCode} Internal Server Error`)); } if (response.error) { if (response.error.details && response.error.details[0].errorCode === 'UNREGISTERED') { client.unregisteredTokens.push(device); } else { return doneCallback(response.error); } } doneCallback(); } catch (err) { errorHandler(err); } }); request.on('error', errorHandler); request.end(); }