TelegramPWA/src/util/pushNotifications.ts

126 lines
4.2 KiB
TypeScript

import { callApi } from '../api/gramjs';
import { DEBUG } from '../config';
import { getDispatch, getGlobal } from '../lib/teact/teactn';
import { IS_SERVICE_WORKER_SUPPORTED } from './environment';
function getDeviceToken(subscription: PushSubscription) {
const data = subscription.toJSON();
return JSON.stringify({ endpoint: data.endpoint, keys: data.keys });
}
function checkIfSupported() {
if (!IS_SERVICE_WORKER_SUPPORTED) return false;
if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
if (DEBUG) {
// eslint-disable-next-line no-console
console.log('[PUSH] Push notifications aren\'t supported.');
}
return false;
}
// Check the current Notification permission.
// If its denied, it's a permanent block until the
// user changes the permission
if (Notification.permission === 'denied') {
if (DEBUG) {
// eslint-disable-next-line no-console
console.log('[PUSH] The user has blocked push notifications.');
}
return false;
}
// Check if push messaging is supported
if (!('PushManager' in window)) {
if (DEBUG) {
// eslint-disable-next-line no-console
console.log('[PUSH] Push messaging isn\'t supported.');
}
return false;
}
return true;
}
const expirationTime = 12 * 60 * 60 * 1000; // 12 hours
function checkIfShouldResubscribe(subscription: PushSubscription | null) {
const global = getGlobal();
if (!global.push || !subscription) return true;
if (getDeviceToken(subscription) !== global.push.deviceToken) return true;
return Date.now() - global.push.subscribedAt > expirationTime;
}
async function unsubscribe(subscription: PushSubscription | null) {
const global = getGlobal();
const dispatch = getDispatch();
if (subscription) {
try {
const deviceToken = getDeviceToken(subscription);
await callApi('unregisterDevice', deviceToken);
await subscription.unsubscribe();
dispatch.deleteDeviceToken();
return;
} catch (error) {
if (DEBUG) {
// eslint-disable-next-line no-console
console.log('[PUSH] Unable to unsubscribe from push.', error);
}
}
}
if (global.push) {
await callApi('unregisterDevice', global.push.deviceToken);
dispatch.deleteDeviceToken();
}
}
export async function unsubscribeFromPush() {
if (!checkIfSupported()) return;
const serviceWorkerRegistration = await navigator.serviceWorker.ready;
const subscription = await serviceWorkerRegistration.pushManager.getSubscription();
await unsubscribe(subscription);
}
export async function subscribeToPush() {
if (!checkIfSupported()) return;
const serviceWorkerRegistration = await navigator.serviceWorker.ready;
let subscription = await serviceWorkerRegistration.pushManager.getSubscription();
if (!checkIfShouldResubscribe(subscription)) return;
await unsubscribe(subscription);
try {
subscription = await serviceWorkerRegistration.pushManager.subscribe({
userVisibleOnly: true,
});
const deviceToken = getDeviceToken(subscription);
if (DEBUG) {
// eslint-disable-next-line no-console
console.log('[PUSH] Received push subscription: ', deviceToken);
}
await callApi('registerDevice', deviceToken);
getDispatch().setDeviceToken(deviceToken);
} catch (error) {
if (Notification.permission === 'denied' as NotificationPermission) {
// The user denied the notification permission which
// means we failed to subscribe and the user will need
// to manually change the notification permission to
// subscribe to push messages
if (DEBUG) {
// eslint-disable-next-line no-console
console.log('[PUSH] Permission for Notifications was denied');
}
} else if (DEBUG) {
// A problem occurred with the subscription, this can
// often be down to an issue or lack of the gcm_sender_id
// and / or gcm_user_visible_only
// eslint-disable-next-line no-console
console.log('[PUSH] Unable to subscribe to push.', error);
}
}
}
// Notify service worker that client is fully loaded
export function notifyClientReady() {
if (!navigator.serviceWorker.controller) return;
navigator.serviceWorker.controller.postMessage({
type: 'clientReady',
});
}