Node.js 有条件地向特定用户发送web推送通知

Node.js 有条件地向特定用户发送web推送通知,node.js,reactjs,service-worker,web-push,push-api,Node.js,Reactjs,Service Worker,Web Push,Push Api,我愿意在我的web应用程序上使用web推送通知。我已经在前端(React)设置了serviceWorkers,并在后端(NodeJS)实现了web推送通知。现在我只需要发送特定于用户的通知,这意味着只有特定的用户才能收到这些通知 例如,在我的web应用程序的后端,我将收到一些实时值。比如说,有一个名为 “用户”,其中存储所有用户数据。现在,这些用户将有一个名为“device”的字段,用户将在其中接收数字值,该值将在40-50秒内更新 现在,它们将成为这些值的阈值。例如,如果值达到200以上,则特

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

例如,在我的web应用程序的后端,我将收到一些实时值。比如说,有一个名为 “用户”,其中存储所有用户数据。现在,这些用户将有一个名为“device”的字段,用户将在其中接收数字值,该值将在40-50秒内更新

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

我如何才能创建这样的特定于用户的推送通知,其中通知将仅发送给设备值已达到200以上的用户?。另外,我正在使用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",
      renotify: true,
      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();
}
检查值是否超过阈值,然后发送通知:(例如)。这是一个仅针对单个用户的示例

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",
        })
      );
    }
  }
}


 });
};
exports.checkStatus=async()=>{
schedule.scheduleJob(“*/10*****”,异步()=>{
let subscriptions=wait Subscription.find({});
让电子邮件=”james@mail.com";
让findUser=wait User.findOne({Email});
if(findUser){
如果(findUser.device>200)//findUser.device包含该值
{
对于(设i=0;i
我如何才能使这项工作,只有那些用户谁的设备的价值已经超过200将只收到通知,而不是所有订阅的用户

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",
        })
      );
    }
  }
}


 });
};