简体   繁体   中英

Migrating users from OneSignal to our own database that we push notifications from

I am trying to migrate our subscribers from OneSignal. I exported the endpoint, the keys (auth and P256DH) and I configured the VAPID keys of my OS account on my server.

When I try to send a notification from OS then remove the service worker of OS and use my own, it's sending the same notification that I previously sent through OS (quite odd), and when I programmatically remove the service worker of OS (through the console) and register my own service worker, it's responding with 410 error from chrome ("NotRegistered") and 401 from Firefox ("Request did not validate missing authorization header").
app.js file:

let isSubscribed = false;
let swRegistration = null;
let applicationKey = "PUBLIC_VAPID_KEY_HERE";


function urlB64ToUint8Array(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;
}

if ('serviceWorker' in navigator && 'PushManager' in window) {
    console.log('Service Worker and Push is supported');

    navigator.serviceWorker.register('sw.js')
        .then(function (swReg) {
            console.log('service worker registered');

            swRegistration = swReg;

            swRegistration.pushManager.getSubscription()
                .then(function (subscription) {
                    isSubscribed = !(subscription === null);

                    if (isSubscribed) {
                        console.log('User is subscribed');
                    } else {
                        swRegistration.pushManager.subscribe({
                                userVisibleOnly: true,
                                applicationServerKey: urlB64ToUint8Array(applicationKey)
                            })
                            .then(function (subscription) {
                                console.log(subscription);
                                console.log('User is subscribed');

                                saveSubscription(subscription);

                                isSubscribed = true;
                            })
                            .catch(function (err) {
                                console.log('Failed to subscribe user: ', err);
                            })
                    }
                })
        })
        .catch(function (error) {
            console.error('Service Worker Error', error);
        });
} else {
    console.warn('Push messaging is not supported');
}

function saveSubscription(subscription) {
    let xmlHttp = new XMLHttpRequest();
    xmlHttp.open("POST", "/subscribe");
    xmlHttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState != 4) return;
        if (xmlHttp.status != 200 && xmlHttp.status != 304) {
            console.log('HTTP error ' + xmlHttp.status, null);
        } else {
            console.log("User subscribed to server");
        }
    };

    xmlHttp.send(JSON.stringify(subscription));
}

sw.js file:

let notificationUrl = '';

self.addEventListener('push', function (event) {
    console.log('Push received: ', event);
    let _data = event.data ? JSON.parse(event.data.text()) : {};
    notificationUrl = _data.url;
    event.waitUntil(
        self.registration.showNotification(_data.title, {
            body: _data.message,
            icon: _data.icon,
            tag: _data.tag
        })
    );
});

self.addEventListener('notificationclick', function (event) {
    event.notification.close();

    event.waitUntil(
        clients.matchAll({
            type: "window"
        })
        .then(function (clientList) {
            if (clients.openWindow) {
                return clients.openWindow(notificationUrl);
            }
        })
    );
});

push.js file which pushes notifications:

const express = require('express');
const router = express.Router();
const q = require('q');
const webPush = require('web-push');
const keys = require('./../config/keys');

const mysql = require("mysql");
const pool = mysql.createPool({
  connectionLimit: 10,
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'webpush',
  multipleStatements: true,
  dateStrings: true
});

router.post('/push', (req, res) => {
    const payload = {
        title: req.body.title,
        message: req.body.message,
        url: req.body.url,
        ttl: req.body.ttl,
        icon: req.body.icon,
        image: req.body.image,
        badge: req.body.badge,
        tag: req.body.tag
    };

    pool.query('SELECT * FROM subscriber', (err, subscriptions) => {
        if (err) {
            return console.log(err);
            console.error(`Error occurred while getting subscriptions`);
            return res.status(500).json({
                error: 'Technical error occurred'
            });
        }
        if (!subscriptions.length) {
            console.error(`No subscribers found`);
            return res.status(500).json({
                error: 'Subscribers not found'
            });
        }
        let parallelSubscriptionCalls = subscriptions.map(subscription => {
            return new Promise((resolve, reject) => {
                const pushSubscription = {
                    endpoint: subscription.endpoint,
                    keys: {
                        p256dh: subscription.p256dh,
                        auth: subscription.auth
                    }
                };

                const pushPayload = JSON.stringify(payload);
                const pushOptions = {
                    vapidDetails: {
                        subject: 'https://www.mydomainhere.com',
                        privateKey: keys.privateKey,
                        publicKey: keys.publicKey
                    },
                    TTL: payload.ttl,
                    headers: {}
                };
                webPush.sendNotification(pushSubscription, pushPayload, pushOptions)
                .then((value) => {
                    resolve({
                        status: true,
                        endpoint: subscription.endpoint,
                        data: value
                    });
                }).catch((err) => {
                    reject({
                        status: false,
                        endpoint: subscription.endpoint,
                        data: err
                    });
                });
            });
        });
        q.allSettled(parallelSubscriptionCalls).then((pushResults) => {
            console.info(pushResults);
        });
        res.json({
            data: 'Push triggered'
        });
    })
});

module.exports = router;

subscribe.js file which does the subscription:

const express = require('express');
const router = express.Router();

const mysql = require("mysql");
const pool = mysql.createPool({
  connectionLimit: 10,
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'webpush',
  multipleStatements: true,
  dateStrings: true
});


router.post('/subscribe', (req, res) => {
    const endpoint = req.body.endpoint;
    const auth = req.body.keys.auth;
    const p256dh = req.body.keys.p256dh;

    const subscriptionSet = { endpoint, auth, p256dh }

    pool.getConnection((err, connection) => {
        if (err) {
            console.error(`Error occurred while saving subscription. Err: ${err}`);
            return res.status(500).json({
                error: 'Technical error occurred'
            });
        };

        connection.query('INSERT INTO subscriber SET ?', subscriptionSet, (err, subscription) => {
            if (err) {
                console.error(`Error occurred while saving subscription. Err: ${err}`);
                return res.status(500).json({
                    error: 'Technical error occurred'
                });
            }
            res.json({
                data: 'Subscription saved.'
            })
        })
    });
});

module.exports = router;

Im trying to do the same, how and where did you export the subscribers auth and P256DH from onesignal? because in the csv export, onesignal provides the push_token (endpoint) and not the auth and P256DH. Where would i get the all the users auth and P256DH?

From my understanding you cannot re register the service worker unless the subscriber comes back and visits your domain. However, the service worker updates every day, so what you can do is edit the existing One signal service worker files - delete their content and add your own code or import scripts. Make sure not to change file location or rename the one signal service worker file, it needs to be the same filename. This will count as an 'update' and browsers should automatically replace the contents without any action from users. If there's two OneSignal service worker files then change both.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM