Push notifications: Send notifications through service worker if possible (#1068)

This commit is contained in:
Alexander Zinchuk 2021-05-09 17:44:54 +03:00
parent 272b4c23fd
commit 753a1bb6bf
2 changed files with 92 additions and 67 deletions

View File

@ -7,7 +7,7 @@ enum Boolean {
False = '0'
}
export type NotificationData = {
type PushData = {
custom: {
msg_id?: string;
channel_id?: string;
@ -23,10 +23,17 @@ export type NotificationData = {
description: string;
};
type NotificationData = {
messageId?: number;
chatId?: number;
title: string;
body: string;
};
const clickBuffer: Record<string, NotificationData> = {};
const shownNotifications = new Set();
function getPushData(e: PushEvent | Notification): NotificationData | undefined {
function getPushData(e: PushEvent | Notification): PushData | undefined {
try {
return e.data.json();
} catch (error) {
@ -38,6 +45,46 @@ function getPushData(e: PushEvent | Notification): NotificationData | undefined
}
}
function getChatId(data: PushData) {
if (data.custom.from_id) {
return parseInt(data.custom.from_id, 10);
}
// Chats and channels have negative IDs
if (data.custom.chat_id) {
return parseInt(data.custom.chat_id, 10) * -1;
}
if (data.custom.channel_id) {
return parseInt(data.custom.channel_id, 10) * -1;
}
return undefined;
}
function getMessageId(data: PushData) {
if (!data.custom.msg_id) return undefined;
return parseInt(data.custom.msg_id, 10);
}
function getNotificationData(data: PushData):NotificationData {
return {
chatId: getChatId(data),
messageId: getMessageId(data),
title: data.title || process.env.APP_INFO!,
body: data.description,
};
}
function showNotification({
chatId, messageId, body, title,
}: NotificationData) {
return self.registration.showNotification(title, {
body,
data: { chatId, messageId },
icon: 'icon-192x192.png',
badge: 'icon-192x192.png',
vibrate: [200, 100, 200],
});
}
export function handlePush(e: PushEvent) {
if (DEBUG) {
// eslint-disable-next-line no-console
@ -52,49 +99,19 @@ export function handlePush(e: PushEvent) {
// Do not show muted notifications
if (!data || data.mute === Boolean.True) return;
const notification = getNotificationData(data);
// Dont show already triggered notification
const messageId = getMessageId(data);
if (shownNotifications.has(messageId)) {
shownNotifications.delete(messageId);
if (shownNotifications.has(notification.messageId)) {
shownNotifications.delete(notification.messageId);
return;
}
const title = data.title || process.env.APP_INFO!;
const body = data.description;
e.waitUntil(
self.registration.showNotification(title, {
body,
data,
icon: 'icon-192x192.png',
badge: 'icon-192x192.png',
vibrate: [200, 100, 200],
}),
);
e.waitUntil(showNotification(notification));
}
function getChatId(data: NotificationData) {
if (data.custom.from_id) {
return parseInt(data.custom.from_id, 10);
}
// Chats and channels have negative IDs
if (data.custom.chat_id) {
return parseInt(data.custom.chat_id, 10) * -1;
}
if (data.custom.channel_id) {
return parseInt(data.custom.channel_id, 10) * -1;
}
return undefined;
}
function getMessageId(data: NotificationData) {
if (!data.custom.msg_id) return undefined;
return parseInt(data.custom.msg_id, 10);
}
function focusChatMessage(client: WindowClient, data: NotificationData) {
const chatId = getChatId(data);
const messageId = getMessageId(data);
function focusChatMessage(client: WindowClient, data: {chatId?: number; messageId?: number}) {
const { chatId, messageId } = data;
if (chatId) {
client.postMessage({
@ -147,7 +164,8 @@ export function handleClientMessage(e: ExtendableMessageEvent) {
}
if (e.data.type === 'newMessageNotification') {
// store messageId for already shown notification
const { messageId } = e.data.payload;
shownNotifications.add(messageId);
const notification: NotificationData = e.data.payload;
e.waitUntil(showNotification(notification));
shownNotifications.add(notification.messageId);
}
}

View File

@ -242,33 +242,40 @@ export async function showNewMessageNotification({
body,
} = getNotificationContent(chat, message as ApiMessage);
const notification = new Notification(title, {
body,
icon: 'icon-192x192.png',
badge: 'icon-192x192.png',
tag: message.id.toString(),
vibrate: [200, 100, 200],
});
if (navigator.serviceWorker.controller) {
// notify service worker about new message notification
navigator.serviceWorker.controller.postMessage({
type: 'newMessageNotification',
payload: { messageId: message.id },
});
}
const dispatch = getDispatch();
notification.onclick = () => {
notification.close();
dispatch.focusMessage({
chatId: chat.id,
messageId: message.id,
});
if (window.focus) {
window.focus();
if (checkIfPushSupported()) {
if (navigator.serviceWorker.controller) {
// notify service worker about new message notification
navigator.serviceWorker.controller.postMessage({
type: 'newMessageNotification',
payload: {
title,
body,
chatId: chat.id,
messageId: message.id,
},
});
}
};
} else {
const dispatch = getDispatch();
const notification = new Notification(title, {
body,
icon: 'icon-192x192.png',
badge: 'icon-192x192.png',
tag: message.id.toString(),
vibrate: [200, 100, 200],
});
notification.onclick = () => {
notification.close();
dispatch.focusMessage({
chatId: chat.id,
messageId: message.id,
});
if (window.focus) {
window.focus();
}
};
}
}
// Notify service worker that client is fully loaded