This repository has been archived by the owner on Oct 26, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 21
/
sw.js
83 lines (75 loc) · 2.95 KB
/
sw.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
/* eslint-env serviceworker */
const portTimeoutDuration = 5000
self.addEventListener('install', () => {
self.skipWaiting()
})
self.addEventListener('activate', evt => {
evt.waitUntil(self.clients.claim())
})
self.addEventListener('fetch', event => {
const { request } = event
const { url, method, headers, destination } = request
if (!url.includes(self.registration.scope + 'webtorrent/')) return null
if (url.includes(self.registration.scope + 'webtorrent/keepalive/')) return event.respondWith(new Response())
event.respondWith(clients.matchAll({ type: 'window', includeUncontrolled: true })
.then(clients => {
return new Promise(resolve => {
// Use race condition for whoever controls the response stream
for (const client of clients) {
const messageChannel = new MessageChannel()
const { port1, port2 } = messageChannel
port1.onmessage = event => {
resolve([event.data, messageChannel])
}
client.postMessage({
url,
method,
headers: Object.fromEntries(headers.entries()),
scope: self.registration.scope,
destination,
type: 'webtorrent'
}, [port2])
}
})
})
.then(([data, messageChannel]) => {
if (data.body === 'STREAM' || data.body === 'DOWNLOAD') {
let timeOut = null
return new Response(new ReadableStream({
pull (controller) {
return new Promise(resolve => {
messageChannel.port1.onmessage = event => {
if (event.data) {
controller.enqueue(event.data) // event.data is Uint8Array
} else {
clearTimeout(timeOut)
controller.close() // event.data is null, means the stream ended
messageChannel.port1.onmessage = null
}
resolve()
}
// 'media player' does NOT signal a close on the stream and we cannot close it because it's locked to the reader,
// so we just empty it after 5s of inactivity, the browser will request another port anyways
clearTimeout(timeOut)
if (data.body === 'STREAM') {
timeOut = setTimeout(() => {
controller.close()
messageChannel.port1.postMessage(false) // send timeout
messageChannel.port1.onmessage = null
resolve()
}, portTimeoutDuration)
}
messageChannel.port1.postMessage(true) // send a pull request
})
},
cancel () {
// This event is never executed
messageChannel.port1.postMessage(false) // send a cancel request
}
}), data)
}
return new Response(data.body, data)
})
.catch(console.error)
)
})