File size: 2,926 Bytes
11fcc5a |
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 |
import * as Storage from "$lib/storage";
const networkErrors = [
"TypeError: Failed to fetch",
"TypeError: network error",
];
let attempts = 0;
const fetchFile = async (url: string) => {
const error = async (code: string, retry: boolean = true) => {
attempts++;
// try 3 more times before actually failing
if (retry && attempts <= 3) {
await fetchFile(url);
} else {
self.postMessage({
cobaltFetchWorker: {
error: code,
}
});
return self.close();
}
};
try {
const response = await fetch(url);
if (!response.ok) {
return error("queue.fetch.bad_response");
}
const contentType = response.headers.get('Content-Type')
|| 'application/octet-stream';
const contentLength = response.headers.get('Content-Length');
const estimatedLength = response.headers.get('Estimated-Content-Length');
let expectedSize;
if (contentLength) {
expectedSize = +contentLength;
} else if (estimatedLength) {
expectedSize = +estimatedLength;
}
const reader = response.body?.getReader();
const storage = await Storage.init(expectedSize);
if (!reader) {
return error("queue.fetch.no_file_reader");
}
let receivedBytes = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
await storage.write(value, receivedBytes);
receivedBytes += value.length;
if (expectedSize) {
self.postMessage({
cobaltFetchWorker: {
progress: Math.round((receivedBytes / expectedSize) * 100),
size: receivedBytes,
}
});
}
}
if (receivedBytes === 0) {
return error("queue.fetch.empty_tunnel");
}
const file = Storage.retype(await storage.res(), contentType);
if (contentLength && Number(contentLength) !== file.size) {
return error("queue.fetch.corrupted_file", false);
}
self.postMessage({
cobaltFetchWorker: {
result: file
}
});
} catch (e) {
// retry several times if the error is network-related
if (networkErrors.includes(String(e))) {
return error("queue.fetch.network_error");
}
console.error("error from the fetch worker:");
console.error(e);
return error("queue.fetch.crashed", false);
}
}
self.onmessage = async (event: MessageEvent) => {
if (event.data.cobaltFetchWorker) {
await fetchFile(event.data.cobaltFetchWorker.url);
self.close();
}
}
|