Spaces:
Sleeping
Sleeping
| 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 | |
| } | |
| } | |
| } | |