miru/api fetch/sw.js
unknown bd89f773b1
2020-08-17 20:09:31 +02:00

60 lines
1.9 KiB
JavaScript

// Activate event
// Be sure to call self.clients.claim()
self.addEventListener('activate', evt => {
// `claim()` sets this worker as the active worker for all clients that
// match the workers scope and triggers an `oncontrollerchange` event for
// the clients.
return self.clients.claim()
})
self.addEventListener('fetch', evt => {
const { request } = evt
const { url, method } = request
const headers = [...request.headers]
if (!url.includes(self.registration.scope + 'webtorrent/')) return null
function getConsumer(clients) {
return new Promise((rs, rj) => {
// Use race condition for whoever controls the response stream
for (const client of clients) {
const mc = new MessageChannel()
mc.port1.onmessage = evt => rs([evt.data, mc])
client.postMessage({
url,
method,
headers,
scope: self.registration.scope
}, [mc.port2])
}
})
}
evt.respondWith(
clients.matchAll({ type: 'window', includeUncontrolled: true })
.then(getConsumer)
.then(([data, consumer]) => {
const readable = 'body' in data ? data.body : new ReadableStream({
pull(controller) {
console.log('requesting data')
return new Promise(rs => {
consumer.port1.onmessage = evt => {
evt.data
? controller.enqueue(evt.data) // evt.data is Uint8Array
: controller.close() // evt.data is null, means the stream ended
rs()
}
consumer.port1.postMessage(true) // send a pull request
})
},
cancel() {
// This event is never executed
console.log('request aborted')
consumer.port1.postMessage(false) // send a cancel request
}
})
return new Response(readable, data)
})
.catch(console.error)
)
})