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 { Settings } from "./index.svelte";
|
||||||
import { PUB_VERTD_URL } from "$env/static/public";
|
import { PUB_VERTD_URL } from "$env/static/public";
|
||||||
|
import { log } from "$lib/util/logger";
|
||||||
|
|
||||||
const LOCATIONS = [
|
const LOCATIONS = [
|
||||||
{
|
{ url: "https://eu.vertd.vert.sh" },
|
||||||
latitude: 49.0976,
|
{ url: "https://usa.vertd.vert.sh" },
|
||||||
longitude: 12.4869,
|
|
||||||
url: "https://eu.vertd.vert.sh",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
latitude: 47.6587,
|
|
||||||
longitude: -117.426,
|
|
||||||
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 =
|
export type VertdInner =
|
||||||
| { type: "auto" }
|
| { type: "auto" }
|
||||||
| { type: "eu" }
|
| { type: "eu" }
|
||||||
|
|
@ -40,8 +16,6 @@ export type VertdInner =
|
||||||
export class VertdInstance {
|
export class VertdInstance {
|
||||||
public static instance = new VertdInstance();
|
public static instance = new VertdInstance();
|
||||||
|
|
||||||
private cachedIp = $state<IpInfo | null>(null);
|
|
||||||
|
|
||||||
private inner = $state<VertdInner>({
|
private inner = $state<VertdInner>({
|
||||||
type: "auto",
|
type: "auto",
|
||||||
});
|
});
|
||||||
|
|
@ -81,32 +55,45 @@ export class VertdInstance {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async url() {
|
public async url() {
|
||||||
const reachable = async (url: string) => {
|
const latency = async (url: string) => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(url + "/api/version", {
|
const start = performance.now();
|
||||||
|
await fetch(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
cache: "no-store",
|
cache: "no-store",
|
||||||
|
mode: "no-cors",
|
||||||
});
|
});
|
||||||
return res.ok;
|
return performance.now() - start;
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return Number.POSITIVE_INFINITY;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (this.inner.type) {
|
switch (this.inner.type) {
|
||||||
case "auto": {
|
case "auto": {
|
||||||
if (!this.cachedIp) this.cachedIp = await ip();
|
const results = await Promise.all(
|
||||||
const ipInfo = this.cachedIp;
|
LOCATIONS.map(async ({ url }) => ({
|
||||||
const primary = this.geographicallyOptimalInstance(ipInfo);
|
url,
|
||||||
|
latency: await latency(url),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
// try primary (closest) first
|
const fastest = results
|
||||||
if (await reachable(primary)) return primary;
|
.filter((result) => Number.isFinite(result.latency))
|
||||||
|
.sort((a, b) => a.latency - b.latency)[0];
|
||||||
|
|
||||||
// fall back to other locations
|
const latencySummary = results
|
||||||
for (const location of LOCATIONS) {
|
.map(
|
||||||
if (location.url === primary) continue;
|
(result) =>
|
||||||
if (await reachable(location.url)) return location.url;
|
`${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
|
// if none are reachable, fall back to custom
|
||||||
return Settings.instance.settings.vertdURL;
|
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