Как реализовать сложное поведение с помощью push-уведомлений на Node.js - PullRequest
0 голосов
/ 03 июня 2018

Я экспериментирую с push-уведомлениями, отправленными из приложения Node.js.Следуя некоторым учебникам и примерам, у меня теперь есть работающее мини-приложение, с которого нужно начинать.

То, что оно делает, является очень простым, когда оно загружается в браузер, запускается уведомление, и пользователь видит всплывающее сообщениеup.

Он в основном состоит из четырех файлов: index.js, index.html, worker.js и client.js.

В качестве первого эксперимента я хотел бы реализовать несколькоболее сложное поведение.

Приложение должно запускать уведомление типа A при запуске (как оно уже делает), а затем запускать уведомление типа B каждые 121 минуту.

Это такойвещи возможны или просто невозможны?

Если это возможно, как я могу это сделать?

Для справки я поместил здесь два соответствующих файла:

index.js :

const express = require('express'),
      webPush = require('web-push'),
      bodyParser = require('body-parser'),
      path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'client')));
app.use(bodyParser.json());

const privateVapIdKey = process.env.privVapIdKey,
      publicVapIdKey = process.env.pubVapIdKey;

webPush.setVapidDetails(
    'mailto:myemail@example.com',
    publicVapIdKey,privateVapIdKey);

// Subscribe Route.
app.post('/subscribe',(req,res) => {
    const subscription = req.body; // Get Push Subscription Object.
    res.status(201).json({}); // Send 201. Resource created.

    // Do a lot of useful things ......
    .......
    // Create the PayLoad.
    const payload = JSON.stringify({
        title:'A big title!',
        ........
    });
    // Pass Object to sendNotification.
    webPush.sendNotification(subscription,payload).catch(err => console.error(err));
});

const port = 5003;

const PORT = process.env.PORT || port;
app.listen(PORT, () => console.log(`Listening on ${ PORT }`));

client.js :

const publicVapIdKey = 'my-secret-3453754...pubVapIdKey';

// Chec for ServiceWorker.
if ('serviceWorker' in navigator) {
    send().catch(err => console.error(err));
}


// Register ServiceWorker, Register Push, Send Push.
async function send() {
    console.log("Registering ServiceWorker.");
    const register = await navigator.serviceWorker.register('/worker.js', {
        scope: "/"
    });
    console.log('ServiceWorker registered.');

    console.log("Registering Push.");
    //register.pushManager.uns
    const subscription = await register.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(publicVapIdKey)
    });
    console.log('Push registered.');

    console.log("Sending Push.");
    await fetch('/subscribe', {
        method: 'POST',
        body: JSON.stringify(subscription),
        headers: {
            'content-type': 'application/json'
        }
    });
    console.log('Push sent.');
}


function urlBase64ToUint8Array(base64String) {
    const padding = '='.repeat((4 - base64String.length % 4) % 4);
    const base64 = (base64String + padding)
      .replace(/\-/g, '+')
      .replace(/_/g, '/');

    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
      outputArray[i] = rawData.charCodeAt(i);
    }

    return outputArray;
}

Ответы [ 3 ]

0 голосов
/ 03 июня 2018

Чтобы отправлять уведомления конечной точке, вам нужна ее подписка, поэтому мы должны хранить подписки клиентов:

const subscriptions = [];

app.post('/subscribe',(req,res) => {
  const subscription = req.body;
  // FIXME: Validate subscription!!!
  subscriptions.push(subscription);
  res.status(201).json({});
  webPush.sendNotification(subscription, { title: "A" });
});

Теперь каждые 121 минуту мы просматриваем все подписки и доставляем наше сообщение.B:

const MINS = 60 * 1000;

setInterval(() => {
  for(const subscription of subscriptions) {
     webPush.sendNotification(subscription, {title: "B" });
  }
}, 121 * MINS);

PS: Возможно, вам также следует добавить конечную точку «отписаться», так как в противном случае вы бы доставляли уведомления на мертвые конечные точки когда-нибудь

0 голосов
/ 03 июня 2018

Это возможно! , но я бы посоветовал вам использовать Admin FCM для серверной части: его более новая библиотека, чем web-push , и способ, которым легче отправлять уведомления.

//node.js serverside code 
const FCM = require("firebase-admin");
//fcm-push-notification.json is where all the configurations are
const serviceAccount = require("fcm-push-notification.json");
FCM.initializeApp({
    credential: SERVICE_ACCOUNT,
    databaseURL: DBURL
});
// In your Subscribe Route.
app.post('/subscribe',(req,res) => {
    FCM.messaging()
    .sendToDevice(
    DEVICE_TOKEN,
    {
        data: DATA,
        notification: {
            title: "A big title!",
            body: "HELLO PUSH!"
        }
    }
    )
    .then(res => {
        // do something here
    })
});

вот служащий

// put firebase-messaging-sw.js service worker
// this is to get notified in the background when the tab is closed on not active 
(global => {
  importScripts("https://www.gstatic.com/firebasejs/4.8.1/firebase-app.js");
  importScripts(
    "https://www.gstatic.com/firebasejs/4.8.1/firebase-messaging.js"
  );
  firebase.initializeApp({
    messagingSenderId: SENDER_ID
  });
  const messaging = firebase.messaging();
  console.log("Service Worker started!");
  messaging.setBackgroundMessageHandler(payload => {
    console.log("Message received In background");
    // Customize notification here
    const notificationOptions = {
      body: "Background Message body.",
      icon: "/firebase-logo.png"
    };
    return global.registration.showNotification("TITLE", notificationOptions);
  });
})(self);

в вашем javascript

//to get notified in forground just do this
import firebase from "firebase";

firebase.initializeApp(FCM_CONF);
let messaging = firebase.messaging();
messaging.usePublicVapidKey(VAPID_KEY);

messaging.onMessage(payload => {
    console.log("Message received from foreground ");
});

наконец создайте manifest.json

//create manifest.json with content like this
{
  "gcm_sender_id": SENDER_ID
}

и отправлять уведомление типа B каждые 121 минуту.используйте что-то вроде Later.js

var later = require('later');
 var schedule = later.parse.text('every 121 min');

 var timer = later.setTimeout(() => {
  // fired every 121 minutes
    FCM.messaging()
    .sendToDevice(
    DEVICE_TOKEN,
    {
        data: DATA,
        notification: {
            title: "A big title!",
            body: "HELLO PUSH!"
        }
    }
    )
 }, schedule);
0 голосов
/ 03 июня 2018

Простая синхронизация событий может быть достигнута с помощью setTimeout и setInterval:
https://nodejs.org/api/timers.html
Они работают так же, как в JavaScript на стороне браузера.

Для чего-то более сложного, попробуйте узел-хрон

...