91 lines
2.4 KiB
JavaScript
91 lines
2.4 KiB
JavaScript
import { ProxyAgent, fetch as undiciFetch } from "undici";
|
|
|
|
const DEFAULT_TEST_URL = "https://google.com/";
|
|
const DEFAULT_TIMEOUT_MS = 8000;
|
|
|
|
function getErrorMessage(err) {
|
|
if (!err) return "Unknown error";
|
|
const base = err?.message || String(err);
|
|
const causeCode = err?.cause?.code || err?.code;
|
|
const causeMessage = err?.cause?.message;
|
|
|
|
if (causeMessage && causeMessage !== base) {
|
|
return causeCode ? `${base}: ${causeMessage} (${causeCode})` : `${base}: ${causeMessage}`;
|
|
}
|
|
|
|
if (causeCode && !base.includes(causeCode)) {
|
|
return `${base} (${causeCode})`;
|
|
}
|
|
|
|
return base;
|
|
}
|
|
|
|
function normalizeString(value) {
|
|
if (value === undefined || value === null) return "";
|
|
return String(value).trim();
|
|
}
|
|
|
|
export async function testProxyUrl({ proxyUrl, testUrl, timeoutMs } = {}) {
|
|
const normalizedProxyUrl = normalizeString(proxyUrl);
|
|
if (!normalizedProxyUrl) {
|
|
return { ok: false, status: 400, error: "proxyUrl is required" };
|
|
}
|
|
|
|
const normalizedTestUrl = normalizeString(testUrl) || DEFAULT_TEST_URL;
|
|
const timeoutMsRaw = Number(timeoutMs);
|
|
const normalizedTimeoutMs =
|
|
Number.isFinite(timeoutMsRaw) && timeoutMsRaw > 0
|
|
? Math.min(timeoutMsRaw, 30000)
|
|
: DEFAULT_TIMEOUT_MS;
|
|
|
|
let dispatcher;
|
|
|
|
try {
|
|
try {
|
|
dispatcher = new ProxyAgent({ uri: normalizedProxyUrl });
|
|
} catch (err) {
|
|
return {
|
|
ok: false,
|
|
status: 400,
|
|
error: `Invalid proxy URL: ${err?.message || String(err)}`,
|
|
};
|
|
}
|
|
|
|
const controller = new AbortController();
|
|
const startedAt = Date.now();
|
|
const timer = setTimeout(() => controller.abort(), normalizedTimeoutMs);
|
|
|
|
try {
|
|
const res = await undiciFetch(normalizedTestUrl, {
|
|
method: "HEAD",
|
|
dispatcher,
|
|
signal: controller.signal,
|
|
headers: {
|
|
"User-Agent": "9Router",
|
|
},
|
|
});
|
|
|
|
return {
|
|
ok: res.ok,
|
|
status: res.status,
|
|
statusText: res.statusText,
|
|
url: normalizedTestUrl,
|
|
elapsedMs: Date.now() - startedAt,
|
|
};
|
|
} catch (err) {
|
|
const message =
|
|
err?.name === "AbortError"
|
|
? "Proxy test timed out"
|
|
: getErrorMessage(err);
|
|
return { ok: false, status: 500, error: message };
|
|
} finally {
|
|
clearTimeout(timer);
|
|
}
|
|
} finally {
|
|
try {
|
|
await dispatcher?.close?.();
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
}
|