// place files you want to import through the `$lib` alias in this folder. import { majorAirportIATAs } from '$lib/icao'; interface BandwidthCallback { ( elapsedMs: number, loadedBytes: number, totalBytes: number, bytesPerSecond: number, done: boolean ): boolean; } export async function bandwidthTest( onProgress: BandwidthCallback, onLatency: (latency: number) => void, onServerLocation: (location: string) => void ) { // performance.setResourceTimingBufferSize(100); // performance.clearResourceTimings(); const url = 'https://cdn-test-cloudfront.hf.co/5gb.safetensors'; // const url = 'https://cdn-test-cloudfront.hf.co/15mb.json'; // issue HEAD requests to estimate latency (round trip time), and average let latencySum = 0; const numLatencyTests = 5; for (let i = 0; i < numLatencyTests; i++) { const startTime = performance.now(); const response = await fetch(url, { method: 'HEAD' }); if (!response.ok) { throw new Error(`Network response was not ok: ${response.status}`); } const latency = performance.now() - startTime; latencySum += latency; } onLatency(latencySum / numLatencyTests); const startTime = performance.now(); const response = await fetch(url); if (!response.ok) { throw new Error(`Network response was not ok: ${response.status}`); } // setTimeout(() => { // const entries = performance.getEntriesByType('resource'); // const resourceEntry = entries.find((e) => e.name === url); // if (!resourceEntry) { // return // } // console.log(resourceEntry); // const { requestStart, responseStart } = resourceEntry; // const latency = responseStart - requestStart; // onLatency(latency); // }, 2000); // extract content-length const contentLengthHeader = response.headers.get('content-length'); const totalBytes = contentLengthHeader ? parseInt(contentLengthHeader, 10) : 1e99; // extract pop location let cdnPop = response.headers.get('x-amz-cf-pop'); if (cdnPop !== null) { cdnPop = cdnPop.toUpperCase().slice(0, 3); // try to map to IATA if (cdnPop in majorAirportIATAs) { cdnPop = majorAirportIATAs[cdnPop].city + ', ' + majorAirportIATAs[cdnPop].country; } else { cdnPop = 'Unknown'; } } else { cdnPop = 'Unknown'; } onServerLocation(cdnPop); const reader = response.body.getReader(); let loadedBytes = 0; let lastTimestamp = performance.now(); let lastLoaded = 0; const REPORT_INTERVAL_MS = 500; onProgress(0, loadedBytes, totalBytes, 0, false); let bytesPerSecond = 0; while (true) { const { done, value } = await reader.read(); if (done) { // stream is finished const elapsedMs = performance.now() - startTime; onProgress(elapsedMs, loadedBytes, totalBytes, bytesPerSecond, true); // send analytics data await sendAnalyticsData(bytesPerSecond, latencySum / numLatencyTests, cdnPop, 1.); break; } // `value` is a Uint8Array for this chunk loadedBytes += value.byteLength; // Current time const now = performance.now(); const deltaMs = now - lastTimestamp; if (deltaMs >= REPORT_INTERVAL_MS) { // compute bytes downloaded since last report const deltaBytes = loadedBytes - lastLoaded; // convert ms to seconds const deltaSeconds = deltaMs / 1000; bytesPerSecond = deltaBytes / deltaSeconds; // Invoke callback const elapsedMs = performance.now() - startTime; const stop = onProgress(elapsedMs, loadedBytes, totalBytes, bytesPerSecond, false); if (stop) { // stop the test console.log(`Stopping bandwidth test at ${loadedBytes} bytes after ${elapsedMs} ms`); break; } // Reset our “last” markers lastLoaded = loadedBytes; lastTimestamp = now; } } } interface ClientInfo { clientIp: string; clientLocation: string; } export async function getClientInfo(): Promise { let clientIp = 'Detecting...'; let clientLocation = 'Detecting...'; const res = await fetch('https://ipapi.co/json/'); clientIp = 'Not available'; clientLocation = 'Not available'; if (res.ok) { const data = await res.json(); clientIp = data.ip || 'Unknown'; let location = ''; if (data.city) location += data.city + ', '; if (data.region) location += data.region + ', '; if (data.country_name) location += data.country_name; clientLocation = location || 'Unknown'; } return new Promise((resolve) => resolve({ clientIp, clientLocation }) ); } export async function sendAnalyticsData(bytesPerSecond: number, latency: number, location: string, progress: number) { // send measurements to analytics API const measurements = { bandwidth: bytesPerSecond, latency, location, progress }; console.log('Sending analytics data'); return new Promise((resolve) => { fetch('/analytics', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(measurements) }) .then((response) => { if (!response.ok) { throw new Error(`Network response was not ok: ${response.status}`); } resolve(response); }) .catch((error) => { console.error('Error sending bandwidth data:', error); resolve(null); }); }); }