34 lines
2.3 KiB
TypeScript
34 lines
2.3 KiB
TypeScript
import type { HostLibraryCache } from '../game-files.js';
|
|
|
|
export const TRANSFER_REPORT_FRESH_MS = 30_000;
|
|
|
|
const nonnegative = (value: number | null | undefined): number | null =>
|
|
typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : null;
|
|
|
|
/** Keep byte progress factual; only the elapsed clock advances between host reports. */
|
|
export function gameFileTransferProgress(cache: HostLibraryCache, connected: boolean, now: number) {
|
|
const active = cache.status === 'downloading' || cache.status === 'verifying';
|
|
const complete = cache.status === 'ready' || cache.status === 'outdated';
|
|
const phase = active ? cache.status as 'downloading' | 'verifying' : cache.transfer?.phase ?? null;
|
|
const total = nonnegative(cache.bytesTotal) ?? 0;
|
|
const downloaded = Math.min(total, nonnegative(cache.bytesDownloaded) ?? 0);
|
|
const verified = complete ? total : nonnegative(cache.bytesVerified);
|
|
const phaseBytes = phase === 'verifying' ? verified === null ? null : Math.min(total, verified) : downloaded;
|
|
const transfer = cache.transfer;
|
|
const samePhase = transfer?.phase === phase;
|
|
const reportedAt = Date.parse(cache.updatedAt);
|
|
const reportAge = Number.isFinite(reportedAt) && Number.isFinite(now) ? Math.max(0, now - reportedAt) : null;
|
|
const stale = active && !!transfer && (reportAge === null || reportAge > TRANSFER_REPORT_FRESH_MS);
|
|
const live = active && connected && samePhase && !stale && reportAge !== null;
|
|
const elapsed = nonnegative(transfer?.elapsedSeconds);
|
|
// Stop extrapolating when reports stop. A disconnected or finished host uses its saved duration.
|
|
const elapsedSeconds = elapsed === null ? null : elapsed + (active && connected && samePhase && reportAge !== null
|
|
? Math.min(reportAge, TRANSFER_REPORT_FRESH_MS) / 1000 : 0);
|
|
const rate = nonnegative(transfer?.bytesPerSecond);
|
|
const estimate = nonnegative(transfer?.etaSeconds);
|
|
const hasProgress = phaseBytes !== null && phaseBytes > 0 && phaseBytes < total;
|
|
const bytesPerSecond = live && hasProgress && rate !== null && rate > 0 ? rate : null;
|
|
const etaSeconds = bytesPerSecond !== null && estimate !== null && estimate > 0 ? estimate : null;
|
|
return { active, complete, phase, total, downloaded, verified, phaseBytes, elapsedSeconds, bytesPerSecond, etaSeconds, stale, live };
|
|
}
|