import { log } from "../logger.ts" import { SW } from "./init.ts" function FallbackStreamDownload(size: number, filename?: string, progress?: (position: number) => void) { log({ scope: "*", warn: true }, "downloading to memory because serviceworker is not available") let position = 0 let buffer = new Uint8Array(size) return { close() { const a = document.createElement("a") a.href = URL.createObjectURL(new Blob([buffer], { type: "text/plain" })) a.download = filename ?? "file" a.click() }, abort() { buffer = new Uint8Array(); /* have fun gc */ }, write(chunk: Blob) { const reader = new FileReader(); reader.onload = function (event) { const arr = new Uint8Array(event.target!.result as ArrayBuffer); for (let i = 0; i < arr.length; i++, position++) { buffer[position] = arr[i] } if (progress) progress(position) }; reader.readAsArrayBuffer(chunk); } } } export function StreamDownload({ size, filename, cancel, progress }: { size: number, filename: string, cancel: () => void, progress: (position: number) => void }) { if (!SW) FallbackStreamDownload(size, filename, progress) let position = 0 const path = `/download/${encodeURIComponent(filename ?? "file")}` const { port1, port2 } = new MessageChannel() SW!.postMessage({ path, size }, [port2]) const a = document.createElement("a") a.href = path a.download = filename ?? "file" a.target = "_blank" a.click() port1.onmessage = ev => { if (ev.data.abort) { cancel() port1.close() } } return { close() { port1.postMessage("end") }, abort() { port1.postMessage("abort") }, write(chunk: Blob) { const reader = new FileReader(); reader.onload = function (event) { const arr = new Uint8Array(event.target!.result as ArrayBuffer); port1.postMessage(arr) position += arr.length if (progress) progress(position) }; reader.readAsArrayBuffer(chunk); } } }