-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathMasterServiceWorker.js
134 lines (126 loc) · 4.84 KB
/
MasterServiceWorker.js
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* global location */
/* global self */
/* global caches */
/* global fetch */
class MasterServiceWorker {
constructor () {
this.name = 'ServiceWorker'
this.version = 'v6'
this.precache = [
'./',
'./index.html',
'./manifest.json',
'./favicon.ico',
'./components/controllers/LocalStorage.js',
'./components/pages/BreathingBubble.js',
'./components/dialogs/Dialog.js',
'./components/dialogs/default-/default-.css',
'./components/dialogs/top-slide-in-/top-slide-in-.css',
'./components/dialogs/left-slide-in-/left-slide-in-.css',
'./components/dialogs/left-slide-in-wide-/left-slide-in-wide-.css',
'./components/dialogs/left-slide-in-without-background-/left-slide-in-without-background-.css',
'./components/dialogs/left-slide-in-checkout-/left-slide-in-checkout-.css',
'./components/dialogs/Timer.js',
'./components/pages/FurtherInstructions.js',
'./components/pages/FurtherInstructionsIframe.js',
'./components/pages/RecoveryBreath.js',
'./components/pages/ResultOverview.js',
'./components/pages/RetentionTime.js',
'./event-driven-web-components-prototypes/src/Shadow.js',
'./event-driven-web-components-prototypes/src/WakeLock.js',
'./event-driven-web-components-prototypes/src/controllers/WakeLock.js',
'./event-driven-web-components-router/src/Router.js',
'./img/Surya-Namaskar.jpg',
'./sound/breath.mp3',
'./sound/finishing.mp3',
'./sound/TreeofLifeBasicTrack.mp3',
'./sound/littleGong.mp3',
'./sound/longGong.mp3'
]
this.doNotIntercept = []
this.doIntercept = [location.origin]
}
run () {
this.addInstallEventListener()
this.addActivateEventListener()
this.addFetchEventListener()
this.addMessageChannelEventListener()
}
// onInstall init cache
addInstallEventListener () {
self.addEventListener('install', event => {
self.skipWaiting()
event.waitUntil(caches.open(this.version).then(cache => cache.addAll(this.precache)))
})
}
// onActivate clear old caches to avoid conflict
addActivateEventListener () {
self.addEventListener('activate', event => {
event.waitUntil(caches.keys().then(keyList => Promise.all(keyList.map(key => key !== this.version ? caches.delete(key) : undefined))))
event.waitUntil(self.clients.claim())
})
}
// intercepts fetches, asks cache for fast response and still fetches and caches afterwards
addFetchEventListener () {
self.addEventListener('fetch', event => event.respondWith(
this.doNotIntercept.every(url => !event.request.url.includes(url)) && this.doIntercept.some(url => event.request.url.includes(url))
? new Promise((resolve, reject) => {
let counter = 0
let didResolve = false
const doResolve = response => {
counter++
if (!didResolve) {
if (response) {
didResolve = true
resolve(response)
} else if (counter >= 2) { // two which race, when none resulted in any useful response, reject
reject(response)
}
}
return response || new Error(`No response for ${event.request.url}`)
}
// race fetch vs. cache to resolve
this.getFetch(event).then(response => doResolve(response)).catch(error => { // start fetching and caching
console.info(`Can't fetch ${event.request.url}`, error)
})
this.getCache(event).then(response => doResolve(response)).catch(error => { // grab cache
console.info(`Can't get cache ${event.request.url}`, error)
})
})
: fetch(event.request)
)
)
}
addMessageChannelEventListener() {
// Notify 24h after last document.visibilityState === 'visible'
self.addEventListener('message', event => {
if (event.data !== 'visible') return
clearTimeout(this.messageTimeoutId)
this.messageTimeoutId = setTimeout(() => {
self.registration.showNotification('Start breathing!', {
body: 'It has been more than 24 hours since you were doing the essential breathing technique...',
icon: `${location.origin}/img/android-icon-192x192.png`,
badge: `${location.origin}/img/android-icon-96x96.png`,
lang: 'en-US',
requireInteraction: true
})
}, 1000 * 60 * 60 * 24)
})
}
async getCache (event) {
return caches.match(event.request)
}
async getFetch (event) {
return fetch(event.request, { cache: 'no-store' }).then(
response => caches.open(this.version).then(
cache => {
// console.log('cached', event.request.url)
cache.put(event.request.clone(), response.clone())
return response
}
)
)
}
}
const ServiceWorker = new MasterServiceWorker()
ServiceWorker.run()