import { Mirror } from "@/config/mirrors"; import { BenchmarkAttempt, BenchmarkResult } from "@/types/benchmark"; const ATTEMPTS_PER_MIRROR = 5; const singleAttempt = async ( url: string, did: string, ): Promise => { const fullUrl = `${url}/${did}`; const uniqueUrl = `${fullUrl}?i=${Date.now()}`; return new Promise((resolve) => { const observer = new PerformanceObserver((list) => { const entries = list.getEntries(); const entry = entries.find( (e) => e.entryType === "resource" && e.name === uniqueUrl, ) as PerformanceResourceTiming | undefined; if (entry) { observer.disconnect(); // Use duration for total time, or calculate from start/response const responseTime = entry.duration || (entry.responseEnd - entry.startTime); resolve({ responseTime, status: "success", statusCode: 200, // PerformanceResourceTiming doesn't provide status code }); } }); observer.observe({ entryTypes: ["resource"] }); // Start the fetch fetch(uniqueUrl, { cache: "no-store", }) .then(async (response) => { if (!response.ok) { observer.disconnect(); resolve({ responseTime: 0, status: "error", statusCode: response.status, error: `HTTP ${response.status}`, }); return; } await response.json(); // Consume the response // Wait briefly for PerformanceObserver to capture the entry setTimeout(() => { const entries = performance.getEntriesByName(uniqueUrl, "resource"); if (entries.length > 0) { const entry = entries[0] as PerformanceResourceTiming; const responseTime = entry.duration || (entry.responseEnd - entry.startTime); observer.disconnect(); resolve({ responseTime, status: "success", statusCode: response.status, }); } else { // Fallback if entry not found observer.disconnect(); resolve({ responseTime: 0, status: "error", error: "Performance entry not found", }); } }, 100); }) .catch((error) => { observer.disconnect(); resolve({ responseTime: 0, status: "error", error: error instanceof Error ? error.message : "Unknown error", }); }); }); }; export const benchmarkMirror = async ( mirror: Mirror, did: string, ): Promise => { const attempts: BenchmarkAttempt[] = []; for (let i = 0; i < ATTEMPTS_PER_MIRROR; i++) { const attempt = await singleAttempt(mirror.url, did); attempts.push(attempt); } const successfulAttempts = attempts.filter((a) => a.status === "success"); const avgResponseTime = successfulAttempts.length > 0 ? successfulAttempts.reduce((sum, a) => sum + a.responseTime, 0) / successfulAttempts.length : 0; return { mirrorUrl: mirror.url, implementation: mirror.implementation, attempts, avgResponseTime, status: successfulAttempts.length > 0 ? "success" : "error", }; }; export const benchmarkAllMirrors = async ( mirrors: Mirror[], did: string, ): Promise => { const promises = mirrors.map((mirror) => benchmarkMirror(mirror, did)); return Promise.all(promises); };