Skip to content

Commit

Permalink
Add progress to http loading.
Browse files Browse the repository at this point in the history
  • Loading branch information
i-zolotarenko committed Sep 20, 2023
1 parent 2bb356e commit 695deca
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 4 deletions.
54 changes: 50 additions & 4 deletions packages/p2p-media-loader-core/src/http-loader.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { RequestAbortError, FetchError } from "./errors";
import { Segment } from "./types";
import { HttpRequest } from "./request";
import { HttpRequest, LoadProgress } from "./request";

export function getHttpSegmentRequest(segment: Segment): Readonly<HttpRequest> {
const { promise, abortController } = fetchSegmentData(segment);
const { promise, abortController, progress, startTimestamp } =
fetchSegmentData(segment);
return {
type: "http",
promise,
progress,
startTimestamp,
abort: () => abortController.abort(),
};
}
Expand All @@ -22,14 +25,18 @@ function fetchSegmentData(segment: Segment) {
}
const abortController = new AbortController();

let progress: LoadProgress | undefined;
const loadSegmentData = async () => {
try {
const response = await window.fetch(url, {
headers,
signal: abortController.signal,
});

if (response.ok) return response.arrayBuffer();
if (response.ok) {
progress = monitorFetchProgress(response);
return response.arrayBuffer();
}
throw new FetchError(
response.statusText ?? `Network response was not for ${segmentId}`,
response.status,
Expand All @@ -43,5 +50,44 @@ function fetchSegmentData(segment: Segment) {
}
};

return { promise: loadSegmentData(), abortController };
return {
promise: loadSegmentData(),
abortController,
progress,
startTimestamp: performance.now(),
};
}

function monitorFetchProgress(
response: Response
): Readonly<LoadProgress> | undefined {
const totalLengthString = response.headers.get("Content-Length");
if (totalLengthString === null || !response.body) return;

const totalLength = +totalLengthString;
const progress: LoadProgress = {
percent: 0,
loadedBytes: 0,
totalLength,
};
const reader = response.body.getReader();

const monitor = async () => {
for await (const chunk of readStream(reader)) {
progress.loadedBytes += chunk.length;
progress.percent = (progress.loadedBytes / totalLength) * 100;
}
};
void monitor();
return progress;
}

async function* readStream(
reader: ReadableStreamDefaultReader<Uint8Array>
): AsyncGenerator<Uint8Array> {
while (true) {
const { done, value } = await reader.read();
if (done) break;
yield value;
}
}
8 changes: 8 additions & 0 deletions packages/p2p-media-loader-core/src/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@ export type EngineCallbacks = {
onError: (reason?: unknown) => void;
};

export type LoadProgress = {
percent: number;
loadedBytes: number;
totalLength: number;
};

type RequestBase = {
promise: Promise<ArrayBuffer>;
abort: () => void;
progress?: Readonly<LoadProgress>;
startTimestamp: number;
};

export type HttpRequest = RequestBase & {
Expand Down

0 comments on commit 695deca

Please sign in to comment.