mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-16 09:36:07 +00:00
feat(outbound): add real-delay connection test mode
The HTTP probe reports the warm per-request round-trip, which reads lower than the delay figure client apps show for the same server. Add a third "real" test mode that reuses the temp-instance HTTP probe but reports the cold request's full elapsed time - tunnel establishment included - and skips the warm request. UDP-transport outbounds forced out of the TCP lane still report "http"; in real mode they report "real". The mode joins the TCP/HTTP toggle on the outbounds tab, with the label translated in all 13 locales.
This commit is contained in:
@@ -29,6 +29,8 @@ export function isUdpOutbound(outbound: unknown): boolean {
|
||||
return p === 'wireguard' || p === 'hysteria' || n === 'hysteria' || n === 'kcp' || n === 'quic';
|
||||
}
|
||||
|
||||
export type OutboundTestMode = 'tcp' | 'http' | 'real';
|
||||
|
||||
export type { OutboundTrafficRow, OutboundTestResult };
|
||||
|
||||
export type XraySettingsValue = z.infer<typeof XraySettingsValueSchema>;
|
||||
@@ -289,7 +291,7 @@ export function useXraySetting(): UseXraySettingResult {
|
||||
const testOutbound = useCallback(
|
||||
async (index: number, outbound: unknown, mode = 'tcp'): Promise<OutboundTestResult | null> => {
|
||||
if (!outbound) return null;
|
||||
const effMode = isUdpOutbound(outbound) ? 'http' : mode;
|
||||
const effMode = mode === 'tcp' && isUdpOutbound(outbound) ? 'http' : mode;
|
||||
setOutboundTestStates((prev) => ({
|
||||
...prev,
|
||||
[index]: { testing: true, result: null, mode: effMode },
|
||||
@@ -306,7 +308,7 @@ export function useXraySetting(): UseXraySettingResult {
|
||||
const testSubscriptionOutbound = useCallback(
|
||||
async (tag: string, outbound: unknown, mode = 'tcp'): Promise<OutboundTestResult | null> => {
|
||||
if (!outbound || !tag) return null;
|
||||
const effMode = isUdpOutbound(outbound) ? 'http' : mode;
|
||||
const effMode = mode === 'tcp' && isUdpOutbound(outbound) ? 'http' : mode;
|
||||
setSubscriptionTestStates((prev) => ({
|
||||
...prev,
|
||||
[tag]: { testing: true, result: null, mode: effMode },
|
||||
@@ -334,6 +336,7 @@ export function useXraySetting(): UseXraySettingResult {
|
||||
// HTTP batches stay homogeneous (all template or all subscription) so a
|
||||
// tag shared between a template and a subscription outbound can't collide
|
||||
// inside one batch, and each batch's results route to one state map.
|
||||
const probeMode = mode === 'real' ? 'real' : 'http';
|
||||
const httpTplQueue: { index: number; outbound: unknown }[] = [];
|
||||
const httpSubQueue: { tag: string; outbound: unknown }[] = [];
|
||||
const enqueue = (ob: { tag?: string; protocol?: string }, kind: 'tpl' | 'sub', index: number, tag: string) => {
|
||||
@@ -342,7 +345,7 @@ export function useXraySetting(): UseXraySettingResult {
|
||||
// freedom ("direct") and dns aren't proxies — skip them in every mode.
|
||||
if (proto === 'freedom' || proto === 'dns') return;
|
||||
if (kind === 'sub' && !tag) return;
|
||||
const toHttp = mode === 'http' || isUdpOutbound(ob);
|
||||
const toHttp = mode !== 'tcp' || isUdpOutbound(ob);
|
||||
if (kind === 'tpl') {
|
||||
if (toHttp) httpTplQueue.push({ index, outbound: ob });
|
||||
else tcpQueue.push({ kind: 'tpl', index, outbound: ob });
|
||||
@@ -376,10 +379,10 @@ export function useXraySetting(): UseXraySettingResult {
|
||||
const chunk = httpTplQueue.slice(at, at + HTTP_BATCH_CHUNK);
|
||||
setOutboundTestStates((prev) => {
|
||||
const next = { ...prev };
|
||||
for (const item of chunk) next[item.index] = { testing: true, result: null, mode: 'http' };
|
||||
for (const item of chunk) next[item.index] = { testing: true, result: null, mode: probeMode };
|
||||
return next;
|
||||
});
|
||||
const results = await postOutboundTestBatch(chunk.map((c) => c.outbound), 'http');
|
||||
const results = await postOutboundTestBatch(chunk.map((c) => c.outbound), probeMode);
|
||||
setOutboundTestStates((prev) => {
|
||||
const next = { ...prev };
|
||||
chunk.forEach((item, i) => {
|
||||
@@ -394,10 +397,10 @@ export function useXraySetting(): UseXraySettingResult {
|
||||
const chunk = httpSubQueue.slice(at, at + HTTP_BATCH_CHUNK);
|
||||
setSubscriptionTestStates((prev) => {
|
||||
const next = { ...prev };
|
||||
for (const item of chunk) next[item.tag] = { testing: true, result: null, mode: 'http' };
|
||||
for (const item of chunk) next[item.tag] = { testing: true, result: null, mode: probeMode };
|
||||
return next;
|
||||
});
|
||||
const results = await postOutboundTestBatch(chunk.map((c) => c.outbound), 'http');
|
||||
const results = await postOutboundTestBatch(chunk.map((c) => c.outbound), probeMode);
|
||||
setSubscriptionTestStates((prev) => {
|
||||
const next = { ...prev };
|
||||
chunk.forEach((item, i) => {
|
||||
|
||||
Reference in New Issue
Block a user