feat(outbound): batched connection tester with direct timed HTTP probes

Replace the per-outbound burstObservatory polling (one temp xray spawn +
up to 15s of /debug/vars polling per outbound, serialised) with one
shared temp xray instance per batch: every tested outbound gets its own
loopback SOCKS inbound plus an inboundTag->outboundTag routing rule, and
the panel times a real HTTP request through each one in parallel. The
probe returns as soon as the response lands and records the HTTP status
plus an httptrace breakdown (proxy connect / TLS via outbound / first
byte) shown in the result popover.

New POST /panel/api/xray/testOutbounds endpoint (array in, results in
input order, max 50); the legacy /testOutbound endpoint now delegates to
the same engine. Test All chunks HTTP probes 16 per request, and a batch
whose shared process never comes up (one structurally-broken outbound
poisons the config) retries each item in an isolated instance so the
broken outbound reports xray's real error while the rest still test.
This commit is contained in:
MHSanaei
2026-06-12 16:55:53 +02:00
parent 85983eec1a
commit 5716ae5987
27 changed files with 1333 additions and 416 deletions
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "فشل اختبار المخرج",
"testModeTooltip": "TCP: فحص dial سريع. HTTP: طلب كامل عبر xray.",
"testAll": "اختبار الكل",
"httpStatus": "حالة HTTP",
"breakdownConnect": "اتصال البروكسي",
"breakdownTls": "TLS عبر الصادر",
"breakdownTtfb": "أول بايت",
"nordvpn": "NordVPN",
"accessToken": "رمز الوصول",
"country": "الدولة",
+4
View File
@@ -1387,6 +1387,10 @@
"testError": "Failed to test outbound",
"testModeTooltip": "TCP: fast dial-only probe. HTTP: full request through xray.",
"testAll": "Test all",
"httpStatus": "HTTP status",
"breakdownConnect": "Proxy connect",
"breakdownTls": "TLS via outbound",
"breakdownTtfb": "First byte",
"nordvpn": "NordVPN",
"accessToken": "Access Token",
"country": "Country",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "Error al probar la salida",
"testModeTooltip": "TCP: sonda rápida solo de dial. HTTP: petición completa a través de xray.",
"testAll": "Probar todo",
"httpStatus": "Estado HTTP",
"breakdownConnect": "Conexión al proxy",
"breakdownTls": "TLS vía salida",
"breakdownTtfb": "Primer byte",
"nordvpn": "NordVPN",
"accessToken": "Token de acceso",
"country": "País",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "خطا در تست خروجی",
"testModeTooltip": "TCP: فقط dial سریع. HTTP: درخواست کامل از طریق xray.",
"testAll": "تست همه",
"httpStatus": "وضعیت HTTP",
"breakdownConnect": "اتصال پروکسی",
"breakdownTls": "TLS از طریق خروجی",
"breakdownTtfb": "اولین بایت",
"nordvpn": "NordVPN",
"accessToken": "توکن دسترسی",
"country": "کشور",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "Gagal menguji outbound",
"testModeTooltip": "TCP: probe dial-only cepat. HTTP: permintaan penuh via xray.",
"testAll": "Tes semua",
"httpStatus": "Status HTTP",
"breakdownConnect": "Koneksi proxy",
"breakdownTls": "TLS melalui outbound",
"breakdownTtfb": "Byte pertama",
"nordvpn": "NordVPN",
"accessToken": "Token Akses",
"country": "Negara",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "アウトバウンドのテストに失敗しました",
"testModeTooltip": "TCP: 高速 dial-only プローブ。HTTP: xray を経由した完全リクエスト。",
"testAll": "すべてテスト",
"httpStatus": "HTTPステータス",
"breakdownConnect": "プロキシ接続",
"breakdownTls": "アウトバウンド経由のTLS",
"breakdownTtfb": "最初のバイト",
"nordvpn": "NordVPN",
"accessToken": "アクセストークン",
"country": "国",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "Falha ao testar saída",
"testModeTooltip": "TCP: sondagem rápida apenas de dial. HTTP: requisição completa pelo xray.",
"testAll": "Testar todos",
"httpStatus": "Status HTTP",
"breakdownConnect": "Conexão do proxy",
"breakdownTls": "TLS via saída",
"breakdownTtfb": "Primeiro byte",
"nordvpn": "NordVPN",
"accessToken": "Token de Acesso",
"country": "País",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "Не удалось протестировать исходящее подключение",
"testModeTooltip": "TCP: быстрый dial-only probe. HTTP: полный запрос через xray.",
"testAll": "Тестировать все",
"httpStatus": "HTTP-статус",
"breakdownConnect": "Подключение к прокси",
"breakdownTls": "TLS через исходящий",
"breakdownTtfb": "Первый байт",
"nordvpn": "NordVPN",
"accessToken": "Токен доступа",
"country": "Страна",
+4
View File
@@ -1385,6 +1385,10 @@
"testError": "Giden bağlantı test edilemedi",
"testModeTooltip": "TCP: hızlı sadece arama (dial-only) testi. HTTP: Xray üzerinden tam istek.",
"testAll": "Tümünü Test Et",
"httpStatus": "HTTP durumu",
"breakdownConnect": "Proxy bağlantısı",
"breakdownTls": "Giden üzerinden TLS",
"breakdownTtfb": "İlk bayt",
"nordvpn": "NordVPN",
"accessToken": "Erişim Jetonu",
"country": "Ülke",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "Не вдалося протестувати вихідне з'єднання",
"testModeTooltip": "TCP: швидкий dial-only probe. HTTP: повний запит через xray.",
"testAll": "Тестувати всі",
"httpStatus": "HTTP-статус",
"breakdownConnect": "Підключення до проксі",
"breakdownTls": "TLS через вихідний",
"breakdownTtfb": "Перший байт",
"nordvpn": "NordVPN",
"accessToken": "Токен доступу",
"country": "Країна",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "Không thể kiểm tra đầu ra",
"testModeTooltip": "TCP: probe dial nhanh. HTTP: yêu cầu đầy đủ qua xray.",
"testAll": "Kiểm tra tất cả",
"httpStatus": "Trạng thái HTTP",
"breakdownConnect": "Kết nối proxy",
"breakdownTls": "TLS qua outbound",
"breakdownTtfb": "Byte đầu tiên",
"nordvpn": "NordVPN",
"accessToken": "Mã truy cập",
"country": "Quốc gia",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "测试出站失败",
"testModeTooltip": "TCP: 快速 dial-only 探测。HTTP: 通过 xray 的完整请求。",
"testAll": "全部测试",
"httpStatus": "HTTP 状态",
"breakdownConnect": "代理连接",
"breakdownTls": "经由出站的 TLS",
"breakdownTtfb": "首字节",
"nordvpn": "NordVPN",
"accessToken": "访问令牌",
"country": "国家",
+4
View File
@@ -1384,6 +1384,10 @@
"testError": "測試出站失敗",
"testModeTooltip": "TCP: 快速 dial-only 探測。HTTP: 透過 xray 的完整請求。",
"testAll": "全部測試",
"httpStatus": "HTTP 狀態",
"breakdownConnect": "代理連線",
"breakdownTls": "經由出站的 TLS",
"breakdownTtfb": "首位元組",
"nordvpn": "NordVPN",
"accessToken": "訪問令牌",
"country": "國家",