Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 51 additions & 70 deletions src/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,35 +96,6 @@ function sortSplats32({
return { activeSplats, readback, ordering };
}

async function fetchRange({
url,
requestHeader,
withCredentials,
offset,
bytes,
}: {
url: string;
requestHeader?: Record<string, string>;
withCredentials?: string;
offset?: number;
bytes?: number;
}): Promise<Uint8Array> {
const request = new Request(url, {
headers: requestHeader ? new Headers(requestHeader) : undefined,
credentials: withCredentials ? "include" : "same-origin",
});
if (offset !== undefined && bytes !== undefined) {
request.headers.set("Range", `bytes=${offset}-${offset + bytes - 1}`);
}
const response = await fetch(request);
if (!response.ok || !response.body) {
throw new Error(
`Failed to fetch "${url}": ${response.status} ${response.statusText}`,
);
}
return new Uint8Array(await response.arrayBuffer());
}

async function decodeBytesUrl({
decoder,
fileBytes,
Expand All @@ -144,13 +115,17 @@ async function decodeBytesUrl({
chunkedLength?: number;
sendStatus: (data: unknown) => void;
}) {
let readStream: ReadableStream;
let streamLength = 0;

if (fileBytes) {
const CHUNK_SIZE = 1048576; // 1 MB
for (let i = 0; i < fileBytes.length; i += CHUNK_SIZE) {
decoder.push(
fileBytes.subarray(i, Math.min(i + CHUNK_SIZE, fileBytes.length)),
);
}
readStream = new ReadableStream({
start(controller) {
controller.enqueue(fileBytes);
controller.close();
},
});
streamLength = fileBytes.length;
} else if (url) {
const request = new Request(url, {
headers: requestHeader ? new Headers(requestHeader) : undefined,
Expand All @@ -163,49 +138,55 @@ async function decodeBytesUrl({
`Failed to fetch "${url}": ${response.status} ${response.statusText}`,
);
}
const readStream = response.body.getReader();
readStream = response.body;
const contentLength = Number.parseInt(
response.headers.get("Content-Length") || "0",
);
const total = Number.isNaN(contentLength) ? 0 : contentLength;
let loaded = 0;

while (true) {
const { done, value } = await readStream.read();
if (done) {
readStream.releaseLock();
break;
}
loaded += value.length;
sendStatus({ loaded, total });

decoder.push(value);
}
streamLength = Number.isNaN(contentLength) ? 0 : contentLength;
} else if (chunked) {
let loaded = 0;
const total = chunkedLength ?? 0;
while (true) {
const readNextChunk: Promise<Uint8Array> = new Promise((resolve) => {
nextChunkWaiter = resolve;
});
sendStatus({ nextChunk: true });
const nextChunk = await readNextChunk;

if (nextChunk.length === 0) {
break;
}

decoder.push(nextChunk);
loaded += nextChunk.length;
sendStatus({ progress: { loaded, total } });
}
if (total === 0) {
sendStatus({ progress: { loaded, total: loaded } });
}
readStream = new ReadableStream({
async start(controller) {
async function readNext() {
const readNextChunk: Promise<Uint8Array> = new Promise((resolve) => {
nextChunkWaiter = resolve;
});
sendStatus({ nextChunk: true });
const nextChunk = await readNextChunk;

if (nextChunk.length === 0) {
controller.close();
return true;
}

controller.enqueue(nextChunk);
return false;
}

let final: boolean;
do {
final = await readNext();
} while (!final);
},
});
streamLength = chunkedLength ?? 0;
} else {
throw new Error("No url or fileBytes provided");
}

const reader = readStream.getReader();
let loaded = 0;
while (true) {
const { done, value } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
loaded += value.length;
sendStatus({ loaded, total: streamLength });

decoder.push(value);
}

const decoded = decoder.finish();
return decoded;
}
Expand Down
Loading