有条件地向特定用户发送网络推送通知

问题描述

我愿意在我的网络应用上使用网络推送通知。我已经在前端(React)上设置了 serviceWorkers,并在我的后端(NodeJS)上实现了网络推送通知。现在我只需要发送特定于用户通知,这意味着只有特定用户才能收到这些通知

例如在我的网络应用程序的后端,我将收到一些实时值。说,有一个名为的集合 “用户”将存储所有用户的数据。现在,这些用户将拥有一个名为“设备”的字段,用户将在该字段中收到将在 40-50 秒内更新的数值。

现在,它们将成为这些值的阈值。说,例如如果该值达到 200 以上,则该特定用户应收到推送通知,让他们知道设备已达到限制。

我如何才能创建此类特定于用户的推送通知,其中通知将仅发送给设备价值已达到 200 以上的用户? P.S 我使用 Mongoose 作为数据库

前端代码(react.js)

sw.js:

self.addEventListener("notificationclick",function (event) {
  // on Notification click
  let notification = event.notification;
  let action = event.action;

  console.log("Notification====>",notification);

  if (action === "confirm") {
    console.log("Confirm clicked");
    notification.close(); // Closes the notifcation
  } else {
    event.waitUntil(
      clients.matchAll().then(function (clis) {
        var client = clis.find(function (c) {
          return c.visibilityState === "visible";
        });

        if (client !== undefined) {
          // found open window
          client.navigate("http://localhost:3000"); // means website opens on the same tab where user is on
          client.focus();
        } else {
          // if client's window was not open
          clients.openWindow("http://localhost:3000"); // when browser window is closed,open website
        }
        notification.close();
      })
    );
    console.log(action); // name of action,basically id
  }
});

self.addEventListener("notificationclose",function (event) {
  console.log("Notification closed",event);
});

// triggers when we get an incoming push message
self.addEventListener("push",function (event) {
  console.log("Push notifications recieved from eventListner",event);
  var data = { title: "New!",content: "New things" };

  if (event.data) {
    // check if payload exists(from backend)
    data = JSON.parse(event.data.text()); // recieve payload & store
  }

  var options = {
    body: data.content,icon: "https://iconarchive.com/download/i90141/icons8/windows-8/Cinema-Avengers.ico",tag: "id1",renotify: true,};

  event.waitUntil(self.registration.showNotification(data.title,options));
});

swReg.js:

if ("serviceWorker" in navigator) {
  console.log("Registering service worker");

  navigator.serviceWorker
    .register("/sw.js")
    .then(() => {
      console.log("Service Worker has been registered");
    })
    .catch((err) => console.error(err));
}


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;
}

function displayConfirmNotification() {
  if ("serviceWorker" in navigator) {
    const options = {
      body: "After subscription managing done",// icon: "/src/assets/img/pattern_react.png",// tag:"" ==> in advanced options.
      vibrate: [100,50,200],// badge:""
      tag: "confirm",actions: [
        { action: "confirm",title: "okay" },// optnl icon:""
        { action: "cancel",title: "cancel" },],};

    navigator.serviceWorker.ready.then(function (swreg) {
      swreg.showNotification("Successfully subscribed sW",options);
    });
  }
}

function configPushSub() {
  if (!("serviceWorker" in navigator)) {
    return;
  }
  var reg;
  navigator.serviceWorker.ready
    .then(function (swreg) {
      // access to sW registration
      reg = swreg;
      return swreg.pushManager.getSubscription(); // returns any existing subscription
    })
    .then(function (sub) {
      // sub holds the current subscription,if subscription doesn't exist then it returns null
      if (sub === null) {
        // Create a new subscription

        var vapidPublicKey = KEY;

        var convertedPublicKey = urlBase64ToUint8Array(vapidPublicKey);

        return reg.pushManager.subscribe({
          userVisibleOnly: true,// for security
          applicationServerKey: convertedPublicKey,// for security & server storage
        }); // create new subscription
      } else {
        // We already have a subscription
      }
    })
    .then(function (newSub) {
      // have to pass this subscription(new one) to backend
      console.log("New subb =======>",newSub);
      return fetch("http://localhost:8000/subscribetoPushNotifications",{
        method: "POST",headers: {
          "Content-Type": "application/json",Accept: "application/json",},body: JSON.stringify({
          subscriptionObj: newSub,}),});
    })
    .then(function (res) {
      if (res.ok) {
        displayConfirmNotification();
      }
    })
    .catch(function (e) {
      console.log("err while subbing====>",e);
    });
}

function askForNotificationPermission() {
  Notification.requestPermission(function (result) {
    console.log("User's choice",result);
    if (result !== "granted") {
      console.log("Permission rights not granted");
    } else {
      configPushSub();
      // displayConfirmNotification();
    }
  });
}

if ("Notification" in window) {
  askForNotificationPermission();
}

后端: 订阅 API:

exports.subscribetoPushNotifications = async (req,res) => {
  const { subscriptionObj } = req.body;

  // console.log("Subscription object=====>",subscriptionObj);

  if (subscriptionObj != undefined || subscriptionObj != null) {
    let newSubscription = new Subscription({
      pushSubscription: subscriptionObj,});

    await newSubscription.save();

    if (newSubscription) {
      console.log(newSubscription);
      return res.status(200).send("Subscription made");
    } else {
      console.log("Not subbed");
      return res.status(400).send("Subscription not made");
    }
  } else {
    console.log("Sub obj is null");
    return res.status(400).send("Sub obj was null");
  }
};

检查值是否超过阈值,然后发送通知:(例如目的)。这是仅适用于单个用户的示例。

exports.checkStatus = async () => {

  schedule.scheduleJob("*/10 * * * * *",async () => {

let subscriptions = await Subscription.find({});

let Email = "james@mail.com";
let findUser = await User.findOne({ Email });

if (findUser) {     
 
  if (findUser.device > 200) // findUser.device contains the value 
   {
    for (let i = 0; i < subscriptions.length; i++) { //Notification will be sent to all users which I don't want.
      webpush.sendNotification(
        subscriptions[i].pushSubscription,JSON.stringify({
          title: "Alert",content: "Value has reached it's limit",})
      );
    }
  }
}


 });
};

我如何才能使这项工作正常进行,以便只有设备价值超过 200 的用户才会收到通知,而不是所有订阅用户

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)