Initial public release v1.7.233
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
import { ALLOCATION_UNIT_SIZE } from "./constants";
|
||||
|
||||
export type DownloadCompletionSource =
|
||||
| "content-range"
|
||||
| "content-length"
|
||||
| "provider-metadata"
|
||||
| "stream-end";
|
||||
|
||||
export type DownloadCompletionPlan = {
|
||||
expectedTotal: number | null;
|
||||
source: DownloadCompletionSource;
|
||||
canFinishEarly: boolean;
|
||||
};
|
||||
|
||||
export function planDownloadCompletion(args: {
|
||||
existingBytes: number;
|
||||
responseStatus: number;
|
||||
contentLength: number;
|
||||
totalFromRange: number | null;
|
||||
knownTotal: number | null;
|
||||
correctedTotal: number | null;
|
||||
}): DownloadCompletionPlan {
|
||||
const existingBytes = Math.max(0, Math.floor(Number(args.existingBytes) || 0));
|
||||
const responseStatus = Math.floor(Number(args.responseStatus) || 0);
|
||||
const contentLength = Math.max(0, Math.floor(Number(args.contentLength) || 0));
|
||||
const totalFromRange = Number.isFinite(args.totalFromRange || NaN)
|
||||
? Math.max(0, Math.floor(args.totalFromRange || 0))
|
||||
: 0;
|
||||
const correctedTotal = Number.isFinite(args.correctedTotal || NaN)
|
||||
? Math.max(0, Math.floor(args.correctedTotal || 0))
|
||||
: 0;
|
||||
const knownTotal = Number.isFinite(args.knownTotal || NaN)
|
||||
? Math.max(0, Math.floor(args.knownTotal || 0))
|
||||
: 0;
|
||||
|
||||
if (correctedTotal > 0) {
|
||||
return {
|
||||
expectedTotal: correctedTotal,
|
||||
source: totalFromRange > 0 ? "content-range" : "content-length",
|
||||
canFinishEarly: true
|
||||
};
|
||||
}
|
||||
|
||||
if (totalFromRange > 0) {
|
||||
return {
|
||||
expectedTotal: totalFromRange,
|
||||
source: "content-range",
|
||||
canFinishEarly: true
|
||||
};
|
||||
}
|
||||
|
||||
if (contentLength > 0) {
|
||||
return {
|
||||
expectedTotal: responseStatus === 206 ? existingBytes + contentLength : contentLength,
|
||||
source: "content-length",
|
||||
canFinishEarly: true
|
||||
};
|
||||
}
|
||||
|
||||
if (knownTotal > 0) {
|
||||
return {
|
||||
expectedTotal: knownTotal,
|
||||
source: "provider-metadata",
|
||||
canFinishEarly: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
expectedTotal: null,
|
||||
source: "stream-end",
|
||||
canFinishEarly: false
|
||||
};
|
||||
}
|
||||
|
||||
export function reconcileFinalizedSize(
|
||||
streamedBytes: number,
|
||||
statSize: number,
|
||||
preAllocated: boolean
|
||||
): number {
|
||||
const streamed = Math.max(0, Math.floor(Number(streamedBytes) || 0));
|
||||
if (!Number.isFinite(statSize) || statSize < 0) {
|
||||
return streamed;
|
||||
}
|
||||
const onDisk = Math.floor(statSize);
|
||||
if (preAllocated && onDisk > streamed) {
|
||||
return streamed;
|
||||
}
|
||||
return onDisk;
|
||||
}
|
||||
|
||||
export function validateDownloadedFileCompletion(args: {
|
||||
actualBytes: number;
|
||||
plan: DownloadCompletionPlan;
|
||||
toleranceBytes?: number;
|
||||
}): {
|
||||
ok: boolean;
|
||||
totalBytes: number;
|
||||
acceptedMetadataMismatch: boolean;
|
||||
error?: string;
|
||||
} {
|
||||
const actualBytes = Math.max(0, Math.floor(Number(args.actualBytes) || 0));
|
||||
const expectedTotal = Number.isFinite(args.plan.expectedTotal || NaN)
|
||||
? Math.max(0, Math.floor(args.plan.expectedTotal || 0))
|
||||
: 0;
|
||||
const toleranceBytes = Math.max(0, Math.floor(Number(args.toleranceBytes ?? ALLOCATION_UNIT_SIZE) || 0));
|
||||
|
||||
if (
|
||||
expectedTotal > 0 &&
|
||||
(args.plan.source === "content-range" || args.plan.source === "content-length") &&
|
||||
actualBytes + toleranceBytes < expectedTotal
|
||||
) {
|
||||
return {
|
||||
ok: false,
|
||||
totalBytes: expectedTotal,
|
||||
acceptedMetadataMismatch: false,
|
||||
error: `download_underflow:${actualBytes}/${expectedTotal}`
|
||||
};
|
||||
}
|
||||
|
||||
if (actualBytes <= 0 && expectedTotal > 0) {
|
||||
return {
|
||||
ok: false,
|
||||
totalBytes: expectedTotal,
|
||||
acceptedMetadataMismatch: false,
|
||||
error: `download_underflow:${actualBytes}/${expectedTotal}`
|
||||
};
|
||||
}
|
||||
|
||||
if (args.plan.source === "provider-metadata") {
|
||||
if (expectedTotal > 0 && actualBytes + toleranceBytes < expectedTotal) {
|
||||
return {
|
||||
ok: false,
|
||||
totalBytes: expectedTotal,
|
||||
acceptedMetadataMismatch: false,
|
||||
error: `download_underflow:${actualBytes}/${expectedTotal}`
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
totalBytes: actualBytes,
|
||||
acceptedMetadataMismatch: expectedTotal > 0 && Math.abs(actualBytes - expectedTotal) > toleranceBytes
|
||||
};
|
||||
}
|
||||
|
||||
if (args.plan.source === "stream-end") {
|
||||
if (actualBytes <= 0) {
|
||||
return {
|
||||
ok: false,
|
||||
totalBytes: 0,
|
||||
acceptedMetadataMismatch: false,
|
||||
error: "download_underflow:0/0"
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
totalBytes: actualBytes,
|
||||
acceptedMetadataMismatch: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
totalBytes: Math.max(actualBytes, expectedTotal),
|
||||
acceptedMetadataMismatch: false
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user