10 changed files with 457 additions and 45 deletions
@ -1,47 +1,323 @@ |
|||||||
console.log('Push worker placeholder') |
'use strict'; |
||||||
|
|
||||||
|
console.log('[SW] Push worker started') |
||||||
|
|
||||||
|
|
||||||
var port |
var port |
||||||
|
var lastAliveTime = false |
||||||
|
var pendingNotification = false |
||||||
|
var muteUntil = false |
||||||
|
var baseUrl |
||||||
|
switch (location.hostname) { |
||||||
|
case 'localhost': |
||||||
|
baseUrl = 'http://localhost:8000/app/index.html#/im' |
||||||
|
break |
||||||
|
case 'zhukov.github.io': |
||||||
|
baseUrl = 'https://zhukov.github.io/webogram/#/im' |
||||||
|
break |
||||||
|
default: |
||||||
|
case 'web.telegram.org': |
||||||
|
baseUrl = 'https://' + location.hostname + '/#/im' |
||||||
|
} |
||||||
|
|
||||||
self.addEventListener('push', function(event) { |
self.addEventListener('push', function(event) { |
||||||
var obj = event.data.json() |
var obj = event.data.json() |
||||||
console.log('push obj', obj) |
console.log('[SW] push', obj) |
||||||
|
if (!obj.badge) { |
||||||
|
closeAllNotifications(obj, event) |
||||||
|
} else { |
||||||
fireNotification(obj, event) |
fireNotification(obj, event) |
||||||
|
} |
||||||
}) |
}) |
||||||
|
|
||||||
self.onmessage = function(e) { |
self.addEventListener('activate', function(event) { |
||||||
console.log(e) |
event.waitUntil(clients.claim()) |
||||||
port = e.ports[0] |
}) |
||||||
|
|
||||||
|
|
||||||
|
self.addEventListener('message', function(event) { |
||||||
|
console.log('[SW] on message', event.data) |
||||||
|
port = event.ports[0] || event.source |
||||||
|
if (event.data.type == 'alive') { |
||||||
|
lastAliveTime = +(new Date()) |
||||||
|
|
||||||
|
if (pendingNotification && |
||||||
|
port && |
||||||
|
'postMessage' in port) { |
||||||
|
port.postMessage(pendingNotification) |
||||||
|
pendingNotification = false |
||||||
|
} |
||||||
|
} |
||||||
|
if (event.data.type == 'notifications_clear') { |
||||||
|
closeAllNotifications(event.data, event) |
||||||
} |
} |
||||||
|
if (event.data.baseUrl) { |
||||||
|
baseUrl = event.data.baseUrl |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
function fireNotification(obj, event) { |
function fireNotification(obj, event) { |
||||||
|
var nowTime = +(new Date()) |
||||||
|
if (nowTime - lastAliveTime < 60000) { |
||||||
|
console.log('Supress notification because some instance is alive') |
||||||
|
return false |
||||||
|
} |
||||||
|
if (muteUntil && nowTime < muteUntil) { |
||||||
|
console.log('Supress notification because mute for ', (muteUntil - nowTime) / 60000, 'min') |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
var title = obj.title || 'Telegram' |
var title = obj.title || 'Telegram' |
||||||
var body = obj.description || '' |
var body = obj.description || '' |
||||||
var icon = 'img/Telegram72.png' |
var icon = 'img/logo_share.png' |
||||||
|
var peerID |
||||||
|
|
||||||
|
if (obj.custom && obj.custom.channel_id) { |
||||||
|
peerID = -obj.custom.channel_id |
||||||
|
} |
||||||
|
else if (obj.custom && obj.custom.chat_id) { |
||||||
|
peerID = -obj.custom.chat_id |
||||||
|
} |
||||||
|
else { |
||||||
|
peerID = obj.custom && obj.custom.from_id || 0 |
||||||
|
} |
||||||
|
obj.custom.peerID = peerID |
||||||
|
|
||||||
event.waitUntil(self.registration.showNotification(title, { |
var notificationPromise = self.registration.showNotification(title, { |
||||||
body: body, |
body: body, |
||||||
icon: icon |
icon: icon, |
||||||
|
tag: 'peer' + peerID, |
||||||
|
data: obj, |
||||||
|
actions: [ |
||||||
|
{ |
||||||
|
action: 'mute1d', |
||||||
|
title: 'Mute background alerts for 1 day' |
||||||
|
}, |
||||||
|
{ |
||||||
|
action: 'push_settings', |
||||||
|
title: 'Background alerts settings' |
||||||
|
} |
||||||
|
] |
||||||
|
}) |
||||||
|
|
||||||
|
var finalPromise = notificationPromise.then(function (event) { |
||||||
|
if (event && event.notification) { |
||||||
|
pushToNotifications(event.notification) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
event.waitUntil(finalPromise) |
||||||
|
|
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
var notifications = [] |
||||||
|
function pushToNotifications(notification) { |
||||||
|
if (notifications.indexOf(notification) == -1) { |
||||||
|
notifications.push(notification) |
||||||
|
notification.onclose = onCloseNotification |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function onCloseNotification(event) { |
||||||
|
muteUntil = Math.max(muteUntil || 0, +(new Date()) + 600000) // 10 min
|
||||||
|
removeFromNotifications(event.notification) |
||||||
|
} |
||||||
|
|
||||||
|
function removeFromNotifications(notification) { |
||||||
|
console.warn('on close', notification) |
||||||
|
var pos = notifications.indexOf(notification) |
||||||
|
if (pos != -1) { |
||||||
|
notifications.splice(pos, 1) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function closeAllNotifications(obj, event) { |
||||||
|
for (var i = 0, len = notifications.length; i < len; i++) { |
||||||
|
try { |
||||||
|
notifications[i].close() |
||||||
|
} catch (e) {} |
||||||
|
} |
||||||
|
|
||||||
|
event.waitUntil(self.registration.getNotifications({}).then(function(notifications) { |
||||||
|
for (var i = 0, len = notifications.length; i < len; i++) { |
||||||
|
try { |
||||||
|
notifications[i].close() |
||||||
|
} catch (e) {} |
||||||
|
} |
||||||
})) |
})) |
||||||
|
|
||||||
|
notifications = [] |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
self.addEventListener('notificationclick', function(event) { |
self.addEventListener('notificationclick', function(event) { |
||||||
console.log('On notification click: ', event.notification.tag) |
var notification = event.notification |
||||||
event.notification.close() |
console.log('On notification click: ', notification.tag) |
||||||
|
notification.close() |
||||||
|
|
||||||
|
var action = event.action |
||||||
|
if (action == 'mute1d') { |
||||||
|
console.log('[SW] mute for 1d') |
||||||
|
muteUntil = +(new Date()) + 86400000 |
||||||
|
IDBManager.setItem('mute_until', muteUntil.toString()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
// This looks to see if the current is already open and
|
|
||||||
// focuses if it is
|
|
||||||
event.waitUntil(clients.matchAll({ |
event.waitUntil(clients.matchAll({ |
||||||
type: 'window' |
type: 'window' |
||||||
}).then(function(clientList) { |
}).then(function(clientList) { |
||||||
|
notification.data.action = action |
||||||
|
pendingNotification = {type: 'push_click', data: notification.data} |
||||||
for (var i = 0; i < clientList.length; i++) { |
for (var i = 0; i < clientList.length; i++) { |
||||||
var client = clientList[i] |
var client = clientList[i] |
||||||
if ('focus' in client) { |
if ('focus' in client) { |
||||||
return client.focus() |
client.focus() |
||||||
|
;(port || client).postMessage(pendingNotification) |
||||||
|
pendingNotification = false |
||||||
|
return |
||||||
} |
} |
||||||
} |
} |
||||||
if (clients.openWindow) |
if (clients.openWindow) { |
||||||
return clients.openWindow('') |
return clients.openWindow(baseUrl) |
||||||
|
} |
||||||
})) |
})) |
||||||
}) |
}) |
||||||
|
|
||||||
|
self.addEventListener('notificationclose', onCloseNotification) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;(function () { |
||||||
|
var dbName = 'keyvalue' |
||||||
|
var dbStoreName = 'kvItems' |
||||||
|
var dbVersion = 2 |
||||||
|
var openDbPromise |
||||||
|
var idbIsAvailable = self.indexedDB !== undefined && |
||||||
|
self.IDBTransaction !== undefined |
||||||
|
|
||||||
|
function isAvailable () { |
||||||
|
return idbIsAvailable |
||||||
|
} |
||||||
|
|
||||||
|
function openDatabase () { |
||||||
|
if (openDbPromise) { |
||||||
|
return openDbPromise |
||||||
|
} |
||||||
|
|
||||||
|
return openDbPromise = new Promise(function (resolve, reject) { |
||||||
|
try { |
||||||
|
var request = indexedDB.open(dbName, dbVersion) |
||||||
|
var createObjectStore = function (db) { |
||||||
|
db.createObjectStore(dbStoreName) |
||||||
|
} |
||||||
|
if (!request) { |
||||||
|
throw new Exception() |
||||||
|
} |
||||||
|
} catch (error) { |
||||||
|
console.error('error opening db', error.message) |
||||||
|
idbIsAvailable = false |
||||||
|
return $q.reject(error) |
||||||
|
} |
||||||
|
|
||||||
|
var finished = false |
||||||
|
setTimeout(function () { |
||||||
|
if (!finished) { |
||||||
|
request.onerror({type: 'IDB_CREATE_TIMEOUT'}) |
||||||
|
} |
||||||
|
}, 3000) |
||||||
|
|
||||||
|
request.onsuccess = function (event) { |
||||||
|
finished = true |
||||||
|
var db = request.result |
||||||
|
|
||||||
|
db.onerror = function (error) { |
||||||
|
idbIsAvailable = false |
||||||
|
console.error('Error creating/accessing IndexedDB database', error) |
||||||
|
reject(error) |
||||||
|
} |
||||||
|
|
||||||
|
resolve(db) |
||||||
|
} |
||||||
|
|
||||||
|
request.onerror = function (event) { |
||||||
|
finished = true |
||||||
|
idbIsAvailable = false |
||||||
|
console.error('Error creating/accessing IndexedDB database', event) |
||||||
|
reject(event) |
||||||
|
} |
||||||
|
|
||||||
|
request.onupgradeneeded = function (event) { |
||||||
|
finished = true |
||||||
|
console.warn('performing idb upgrade from', event.oldVersion, 'to', event.newVersion) |
||||||
|
var db = event.target.result |
||||||
|
if (event.oldVersion == 1) { |
||||||
|
db.deleteObjectStore(dbStoreName) |
||||||
|
} |
||||||
|
createObjectStore(db) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function setItem (key, value) { |
||||||
|
return openDatabase().then(function (db) { |
||||||
|
try { |
||||||
|
var objectStore = db.transaction([dbStoreName], IDBTransaction.READ_WRITE || 'readwrite').objectStore(dbStoreName) |
||||||
|
var request = objectStore.put(value, key) |
||||||
|
} catch (error) { |
||||||
|
idbIsAvailable = false |
||||||
|
return Promise.reject(error) |
||||||
|
} |
||||||
|
|
||||||
|
return new Promise(function(resolve, reject) { |
||||||
|
request.onsuccess = function (event) { |
||||||
|
resolve(value) |
||||||
|
} |
||||||
|
|
||||||
|
request.onerror = function (error) { |
||||||
|
reject(error) |
||||||
|
} |
||||||
|
}) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function getItem (key) { |
||||||
|
return openDatabase().then(function (db) { |
||||||
|
return new Promise(function(resolve, reject) { |
||||||
|
var objectStore = db.transaction([dbStoreName], IDBTransaction.READ || 'readonly').objectStore(dbStoreName) |
||||||
|
var request = objectStore.get(key) |
||||||
|
|
||||||
|
request.onsuccess = function (event) { |
||||||
|
var result = event.target.result |
||||||
|
if (result === undefined) { |
||||||
|
reject() |
||||||
|
} else { |
||||||
|
resolve(result) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
request.onerror = function (error) { |
||||||
|
reject(error) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
openDatabase() |
||||||
|
|
||||||
|
self.IDBManager = { |
||||||
|
name: 'IndexedDB', |
||||||
|
isAvailable: isAvailable, |
||||||
|
setItem: setItem, |
||||||
|
getItem: getItem |
||||||
|
} |
||||||
|
})() |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
IDBManager.getItem('mute_until').then(function (newMuteUntil) { |
||||||
|
muteUntil = Math.max(muteUntil || 0, newMuteUntil || 0) || false |
||||||
|
}) |
Loading…
Reference in new issue