mirror of https://github.com/VERT-sh/VERT.git
feat: ping servers instead of ip location (#240)
much better for privacy :p - fixes #240
This commit is contained in:
parent
7ebc535fa4
commit
f038dfc453
|
|
@ -1,36 +1,12 @@
|
|||
import { ip, type IpInfo } from "$lib/util/ip";
|
||||
import { Settings } from "./index.svelte";
|
||||
import { PUB_VERTD_URL } from "$env/static/public";
|
||||
import { log } from "$lib/util/logger";
|
||||
|
||||
const LOCATIONS = [
|
||||
{
|
||||
latitude: 49.0976,
|
||||
longitude: 12.4869,
|
||||
url: "https://eu.vertd.vert.sh",
|
||||
},
|
||||
{
|
||||
latitude: 47.6587,
|
||||
longitude: -117.426,
|
||||
url: "https://usa.vertd.vert.sh",
|
||||
},
|
||||
{ url: "https://eu.vertd.vert.sh" },
|
||||
{ url: "https://usa.vertd.vert.sh" },
|
||||
];
|
||||
|
||||
const toRad = (value: number) => (value * Math.PI) / 180;
|
||||
const haversine = (lat1: number, lon1: number, lat2: number, lon2: number) => {
|
||||
const R = 6371; // km
|
||||
const dLat = toRad(lat2 - lat1);
|
||||
const dLon = toRad(lon2 - lon1);
|
||||
const a =
|
||||
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
Math.cos(toRad(lat1)) *
|
||||
Math.cos(toRad(lat2)) *
|
||||
Math.sin(dLon / 2) *
|
||||
Math.sin(dLon / 2);
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
const d = R * c;
|
||||
return d;
|
||||
};
|
||||
|
||||
export type VertdInner =
|
||||
| { type: "auto" }
|
||||
| { type: "eu" }
|
||||
|
|
@ -40,8 +16,6 @@ export type VertdInner =
|
|||
export class VertdInstance {
|
||||
public static instance = new VertdInstance();
|
||||
|
||||
private cachedIp = $state<IpInfo | null>(null);
|
||||
|
||||
private inner = $state<VertdInner>({
|
||||
type: "auto",
|
||||
});
|
||||
|
|
@ -81,32 +55,45 @@ export class VertdInstance {
|
|||
}
|
||||
|
||||
public async url() {
|
||||
const reachable = async (url: string) => {
|
||||
const latency = async (url: string) => {
|
||||
try {
|
||||
const res = await fetch(url + "/api/version", {
|
||||
const start = performance.now();
|
||||
await fetch(url, {
|
||||
method: "GET",
|
||||
cache: "no-store",
|
||||
mode: "no-cors",
|
||||
});
|
||||
return res.ok;
|
||||
return performance.now() - start;
|
||||
} catch {
|
||||
return false;
|
||||
return Number.POSITIVE_INFINITY;
|
||||
}
|
||||
};
|
||||
|
||||
switch (this.inner.type) {
|
||||
case "auto": {
|
||||
if (!this.cachedIp) this.cachedIp = await ip();
|
||||
const ipInfo = this.cachedIp;
|
||||
const primary = this.geographicallyOptimalInstance(ipInfo);
|
||||
const results = await Promise.all(
|
||||
LOCATIONS.map(async ({ url }) => ({
|
||||
url,
|
||||
latency: await latency(url),
|
||||
})),
|
||||
);
|
||||
|
||||
// try primary (closest) first
|
||||
if (await reachable(primary)) return primary;
|
||||
const fastest = results
|
||||
.filter((result) => Number.isFinite(result.latency))
|
||||
.sort((a, b) => a.latency - b.latency)[0];
|
||||
|
||||
// fall back to other locations
|
||||
for (const location of LOCATIONS) {
|
||||
if (location.url === primary) continue;
|
||||
if (await reachable(location.url)) return location.url;
|
||||
}
|
||||
const latencySummary = results
|
||||
.map(
|
||||
(result) =>
|
||||
`${result.url} = ${Number.isFinite(result.latency) ? `${result.latency.toFixed(2)}ms` : "unreachable"}`,
|
||||
)
|
||||
.join("\n");
|
||||
log(
|
||||
["settings", "vertd"],
|
||||
`vertd latency results: ${latencySummary}`,
|
||||
);
|
||||
|
||||
if (fastest) return fastest.url;
|
||||
|
||||
// if none are reachable, fall back to custom
|
||||
return Settings.instance.settings.vertdURL;
|
||||
|
|
@ -125,30 +112,4 @@ export class VertdInstance {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private geographicallyOptimalInstance(ip: IpInfo) {
|
||||
let bestLocation = LOCATIONS[0];
|
||||
let bestDistance = haversine(
|
||||
ip.latitude,
|
||||
ip.longitude,
|
||||
bestLocation.latitude,
|
||||
bestLocation.longitude,
|
||||
);
|
||||
|
||||
for (let i = 1; i < LOCATIONS.length; i++) {
|
||||
const location = LOCATIONS[i];
|
||||
const distance = haversine(
|
||||
ip.latitude,
|
||||
ip.longitude,
|
||||
location.latitude,
|
||||
location.longitude,
|
||||
);
|
||||
if (distance < bestDistance) {
|
||||
bestDistance = distance;
|
||||
bestLocation = location;
|
||||
}
|
||||
}
|
||||
|
||||
return bestLocation.url;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue