committed by
GitHub
11 changed files with 156 additions and 27 deletions
@ -0,0 +1,78 @@ |
|||
const WRITE = 0; |
|||
const PULL = 0; |
|||
const ERROR = 1; |
|||
const ABORT = 1; |
|||
const CLOSE = 2; |
|||
|
|||
class MessagePortSource implements UnderlyingSource { |
|||
private controller?: ReadableStreamController<any>; |
|||
|
|||
constructor (private readonly port: MessagePort) { |
|||
this.port.onmessage = evt => this.onMessage(evt.data); |
|||
} |
|||
|
|||
start (controller: ReadableStreamController<any>) { |
|||
this.controller = controller; |
|||
} |
|||
|
|||
cancel (reason: Error) { |
|||
// Firefox can notify a cancel event, chrome can't
|
|||
// https://bugs.chromium.org/p/chromium/issues/detail?id=638494
|
|||
this.port.postMessage({ type: ERROR, reason: reason.message }); |
|||
this.port.close(); |
|||
} |
|||
|
|||
onMessage (message: { type: number; chunk: Uint8Array; reason: any }) { |
|||
// enqueue() will call pull() if needed when there's no backpressure
|
|||
if (!this.controller) { |
|||
return; |
|||
} |
|||
if (message.type === WRITE) { |
|||
this.controller.enqueue(message.chunk); |
|||
this.port.postMessage({ type: PULL }); |
|||
} |
|||
if (message.type === ABORT) { |
|||
this.controller.error(message.reason); |
|||
this.port.close(); |
|||
} |
|||
if (message.type === CLOSE) { |
|||
this.controller.close(); |
|||
this.port.close(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
self.addEventListener("install", () => { |
|||
(self as any).skipWaiting(); |
|||
}); |
|||
|
|||
self.addEventListener("activate", event /* ExtendableEvent */ => { |
|||
(event as any).waitUntil((self as any).clients.claim()); |
|||
}); |
|||
|
|||
const map = new Map(); |
|||
|
|||
// This should be called once per download
|
|||
// Each event has a dataChannel that the data will be piped through
|
|||
globalThis.addEventListener("message", evt => { |
|||
const data = evt.data; |
|||
if (data.url && data.readablePort) { |
|||
data.rs = new ReadableStream( |
|||
new MessagePortSource(evt.data.readablePort), |
|||
new CountQueuingStrategy({ highWaterMark: 4 }) |
|||
); |
|||
map.set(data.url, data); |
|||
} |
|||
}); |
|||
|
|||
globalThis.addEventListener("fetch", evt => { |
|||
const url = (evt as any).request.url; |
|||
const data = map.get(url); |
|||
if (!data) return null; |
|||
map.delete(url); |
|||
(evt as any).respondWith(new Response(data.rs, { |
|||
headers: data.headers |
|||
})); |
|||
}); |
|||
|
|||
export {}; |
|||
Loading…
Reference in new issue