File size: 4,133 Bytes
6f6d8a6
 
feb8590
 
6f6d8a6
 
 
 
 
 
 
e3d1af9
6f6d8a6
 
 
 
feb8590
 
6f6d8a6
bdb8bb2
 
2fac66c
 
feb8590
 
bdb8bb2
 
 
 
 
 
 
 
 
6f6d8a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
feb8590
 
e3d1af9
 
feb8590
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6f6d8a6
 
 
 
 
 
e3d1af9
6f6d8a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e3d1af9
 
 
 
 
 
6f6d8a6
 
 
 
 
 
 
 
feb8590
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6f6d8a6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// 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 a HEAD request to estimate latency (round trip time)
	let startTime = performance.now();
	const latencyResponse = await fetch(url, { method: 'HEAD' });
	if (!latencyResponse.ok) {
		throw new Error(`Network response was not ok: ${latencyResponse.status}`);
	}
	const latency = performance.now() - startTime;
	onLatency(latency);

	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(latency, 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);
			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<ClientInfo> {
	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
		})
	);
}