Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 1x 1x 1x 1x 1x 1x 1x | // tslint:disable:no-console
// In production, we register a service worker to serve assets from local cache.
import { set, random, get } from "lodash";
import { hashObject, cloneClean, PushNotifications_urlBase64ToUint8Array } from "./common";
import { commitChange } from "./data-change";
import { getDB } from "./db";
import { INotification, notifyUsers } from "./notifications";
import { IDevice, IUser, newData, signObject } from "./user";
export function registerServiceWorker(serviceWorkerUrl: string, deviceId: string, me: IUser, vapidPublicKey: string, appName: string) {
return new Promise<IUser>((resolve, reject) => {
// if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
Iif ('serviceWorker' in navigator) {
// // The URL constructor is available in all browsers that support SW.
// const publicUrl = new URL(
// process.env.PUBLIC_URL!,
// window.location.toString()
// );
// if (publicUrl.origin !== window.location.origin) {
// // Our service worker won't work if PUBLIC_URL is on a different origin
// // from what our page is served on. This might happen if a CDN is used to
// // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
// return reject('origins do not match');
// }
function ready(callbackFunction) {
if (document.readyState != 'loading')
callbackFunction()
else
document.addEventListener("DOMContentLoaded", callbackFunction)
}
ready(async () => {
const registration = await navigator.serviceWorker.register(serviceWorkerUrl)
const user = await registerPushSubscription(registration, deviceId, me, vapidPublicKey, appName)
resolve(user);
})
// window.addEventListener('load', () => {});
}
});
}
async function registerPushSubscription(registration: ServiceWorkerRegistration, deviceId: string, me: IUser, vapidPublicKey: string, appName: string) {
let subscription: PushSubscription = await registration.pushManager.getSubscription();
const db = await getDB();
const hashBefore = hashObject(me);
me = await db.get(me.id);
const device: IDevice = get(me, `devices.${deviceId}`) || { id: deviceId };
device.app = appName;
// if device has no expire time, or has expired, or will expire in 4 days, then renew expire
const DAY_IN_MS = 1000 * 60 * 60 * 24;
const expiresMinus4Days = (device.expires || 0) - (DAY_IN_MS * 4)
Iif (expiresMinus4Days < Date.now()) {
device.expires = Date.now() + DAY_IN_MS * 5; // device expires after 5 days
}
// clean out expired devices
Object.keys(me.devices || {}).forEach(deviceId => {
Iif ((me.devices[deviceId].expires || 0) < Date.now()) {
delete me.devices[deviceId];
}
})
Iif (
!subscription ||
(device.subscriptionExpires || 0) < Date.now()
) {
Iif (subscription) {
await subscription.unsubscribe();
}
// const vapidPublicKey = (await GET('/web-push-public-key')).VAPID_PUBLIC_KEY;
// TODO change this to use the same functions peerstack uses for keys
const convertedVapidKey = PushNotifications_urlBase64ToUint8Array(vapidPublicKey);
// const convertedVapidKey = decodeUint8ArrayFromBaseN(vapidPublicKey);
subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: convertedVapidKey
})
.catch(err => {
console.error('an error was thrown trying to subscribe to notifications')
throw err;
});
device.pushSubscription = subscription as any;
device.subscriptionExpires = Date.now() + DAY_IN_MS * 14; // expire subscription in 14 days
}
set(me, `devices.${deviceId}`, cloneClean(device));
// save object if needed
const hashAfter = hashObject(me);
Iif (hashBefore != hashAfter) {
me.modified += random(100, 1000, false);
signObject(me);
// NOTE note sure this has been completely worked out
// it's very desireable to do partial updates to the user object but
// dataChange's don't allow signatures...
const change = await commitChange(me, { preserveModified: true })[0];
await db.save(me, true);
// TODO only send to trusted users (I'm assuming we'll differentiate at some point)
const users = await db.find('User', 'type') as IUser[];
const notification: INotification = {
...newData(),
type: 'Notification',
dontShow: true,
change,
title: 'User Updated',
}
signObject(notification);
notifyUsers(users, notification);
}
console.log('my devices', me.devices);
return me;
}
|