diff --git a/src/components/IPv6Support.tsx b/src/components/IPv6Support.tsx index 20c6216..932cf6a 100644 --- a/src/components/IPv6Support.tsx +++ b/src/components/IPv6Support.tsx @@ -1,14 +1,16 @@ import { useProxies } from '~/signals' +import { proxyIPv6SupportMap } from '~/signals/ipv6' -export const IPv6Support = (props: { name?: string }) => { - const { proxyIPv6SupportMap } = useProxies() - const support = createMemo(() => proxyIPv6SupportMap()[props.name!] === true) +export const IPv6Support = (props: { name?: string; class?: string }) => { + const { getNowProxyNodeName } = useProxies() + + const support = createMemo(() => { + return proxyIPv6SupportMap()[getNowProxyNodeName(props.name || '')] + }) return ( - - IPv6 - + IPv6 ) } diff --git a/src/components/Latency.tsx b/src/components/Latency.tsx index 55bffab..dd042d9 100644 --- a/src/components/Latency.tsx +++ b/src/components/Latency.tsx @@ -4,9 +4,11 @@ import { latencyQualityMap, useProxies } from '~/signals' export const Latency = (props: { name?: string; class?: string }) => { const [t] = useI18n() - const { latencyMap } = useProxies() + const { getNowProxyNodeName, latencyMap } = useProxies() const [textClassName, setTextClassName] = createSignal('') - const latency = createMemo(() => latencyMap()[props.name!]) + const latency = createMemo(() => { + return latencyMap()[getNowProxyNodeName(props.name || '')] + }) createEffect(() => { setTextClassName('text-success') diff --git a/src/signals/connections.ts b/src/signals/connections.ts index a569a3c..cdc7baf 100644 --- a/src/signals/connections.ts +++ b/src/signals/connections.ts @@ -9,8 +9,10 @@ export type WsMsg = { downloadTotal: number } | null +// DIRECT is from clash +// direct and dns-out is from the example of sing-box official site export const [quickFilterRegex, setQuickFilterRegex] = makePersisted( - createSignal('Direct|direct|dns-out'), + createSignal('DIRECT|direct|dns-out'), { name: 'quickFilterRegex', storage: localStorage, diff --git a/src/signals/ipv6.ts b/src/signals/ipv6.ts new file mode 100644 index 0000000..009b77e --- /dev/null +++ b/src/signals/ipv6.ts @@ -0,0 +1,66 @@ +import { proxyGroupLatencyTestAPI, proxyLatencyTestAPI } from '~/apis' +import { + latencyQualityMap, + latencyTestTimeoutDuration, + urlForIPv6SupportTest, +} from './config' + +export const [proxyIPv6SupportMap, setProxyIPv6SupportMap] = createSignal< + Record +>({}) + +export const proxyIPv6SupportTest = async ( + proxyName: string, + provider: string, +) => { + const urlForTest = urlForIPv6SupportTest() + + if (!urlForTest || urlForTest.length === 0) { + setProxyIPv6SupportMap({}) + + return + } + + let support = false + try { + const { delay } = await proxyLatencyTestAPI( + proxyName, + provider, + urlForTest, + latencyTestTimeoutDuration(), + ) + support = delay > latencyQualityMap().NOT_CONNECTED + } catch { + support = false + } + setProxyIPv6SupportMap((supportMap) => ({ + ...supportMap, + [proxyName]: support, + })) +} + +export const proxyGroupIPv6SupportTest = async (proxyGroupName: string) => { + const urlForTest = urlForIPv6SupportTest() + + if (!urlForTest || urlForTest.length === 0) { + setProxyIPv6SupportMap({}) + + return + } + + const newLatencyMap = await proxyGroupLatencyTestAPI( + proxyGroupName, + urlForTest, + latencyTestTimeoutDuration(), + ) + const newSupportMap = Object.fromEntries( + Object.entries(newLatencyMap).map(([k, v]) => [ + k, + v > latencyQualityMap().NOT_CONNECTED, + ]), + ) + setProxyIPv6SupportMap((supportMap) => ({ + ...supportMap, + ...newSupportMap, + })) +} diff --git a/src/signals/proxies.ts b/src/signals/proxies.ts index dac9930..5eac5ab 100644 --- a/src/signals/proxies.ts +++ b/src/signals/proxies.ts @@ -19,6 +19,12 @@ import { urlForLatencyTest, } from '~/signals' import type { Proxy, ProxyNode, ProxyProvider } from '~/types' +import { + proxyGroupIPv6SupportTest, + proxyIPv6SupportMap, + proxyIPv6SupportTest, + setProxyIPv6SupportMap, +} from './ipv6' type ProxyInfo = { name: string @@ -58,13 +64,32 @@ const [proxyProviders, setProxyProviders] = createSignal< >([]) const [latencyMap, setLatencyMap] = createSignal>({}) -const [proxyIPv6SupportMap, setProxyIPv6SupportMap] = createSignal< - Record ->({}) const [proxyNodeMap, setProxyNodeMap] = createSignal>( {}, ) +const getLatencyFromProxy = ( + proxy: Pick, + url: string, + fallbackDefault = true, +) => { + const extra = proxy.extra?.[url] as Proxy['history'] | undefined + + if (Array.isArray(extra)) { + const delay = extra.at(-1)?.delay + + if (delay) { + return delay + } + } + + if (!fallbackDefault) { + return latencyQualityMap().NOT_CONNECTED + } + + return proxy.history?.at(-1)?.delay ?? latencyQualityMap().NOT_CONNECTED +} + const setProxiesInfo = ( proxies: (ProxyWithProvider | ProxyNodeWithProvider)[], ) => { @@ -72,68 +97,21 @@ const setProxiesInfo = ( const newLatencyMap = { ...latencyMap() } const newProxyIPv6SupportMap = { ...proxyIPv6SupportMap() } - const lastDelay = ( - proxy: Pick, - url: string, - fallbackDefault = true, - ) => { - const extra = proxy.extra?.[url] as Proxy['history'] | undefined - - if (Array.isArray(extra)) { - const delay = extra.at(-1)?.delay - - if (delay) { - return delay - } - } - - if (!fallbackDefault) { - return undefined - } - - return proxy.history?.at(-1)?.delay - } - - const dependedLatencyProxies = {} as Record> - proxies.forEach((proxy) => { const { udp, xudp, type, now, name, provider = '' } = proxy + newProxyNodeMap[proxy.name] = { udp, xudp, type, now, name, provider } + newLatencyMap[proxy.name] = getLatencyFromProxy(proxy, urlForLatencyTest()) - // to solve the problem of the ProxyGroup cannot obtain the latency of the currently used proxy node - // it seems that only clash.core and clash.premium have issues - if (!now) { - newLatencyMap[proxy.name] = - lastDelay(proxy, urlForLatencyTest()) || - latencyQualityMap().NOT_CONNECTED - } else if (newLatencyMap[now] !== undefined) { - newLatencyMap[proxy.name] = newLatencyMap[now] - } else { - const dependencies = dependedLatencyProxies[now] ?? new Set() - dependencies.add(proxy.name) - dependedLatencyProxies[now] = dependencies + // we don't set it when false because sing-box didn't have "extra" so it will always be false + if ( + getLatencyFromProxy(proxy, urlForIPv6SupportTest(), false) > + latencyQualityMap().NOT_CONNECTED + ) { + newProxyIPv6SupportMap[proxy.name] = true } - - const proxyIPv6Support = - (lastDelay(proxy, urlForIPv6SupportTest(), false) ?? 0) > 0 - newProxyIPv6SupportMap[proxy.name] = proxyIPv6Support }) - const independencies = Object.keys(dependedLatencyProxies).filter( - (now) => newLatencyMap[now] !== undefined, - ) - - // maybe we should use Union-Find to implement this - while (independencies.length > 0) { - const now = independencies.shift()! - const delay = newLatencyMap[now]! - - for (const name of dependedLatencyProxies[now]?.values() ?? []) { - newLatencyMap[name] = delay - independencies.push(name) - } - } - batch(() => { setProxyNodeMap(newProxyNodeMap) setLatencyMap(newLatencyMap) @@ -206,58 +184,9 @@ export const useProxies = () => { } } - const proxyIPv6SupportTest = async (proxyName: string, provider: string) => { - const urlForTest = urlForIPv6SupportTest() - - if (!urlForTest || urlForTest.length === 0) { - setProxyIPv6SupportMap({}) - - return - } - - let support = false - try { - const { delay } = await proxyLatencyTestAPI( - proxyName, - provider, - urlForTest, - latencyTestTimeoutDuration(), - ) - support = delay > 0 - } catch { - support = false - } - setProxyIPv6SupportMap((supportMap) => ({ - ...supportMap, - [proxyName]: support, - })) - } - const proxyGroupIPv6SupportTest = async (proxyGroupName: string) => { - const urlForTest = urlForIPv6SupportTest() - - if (!urlForTest || urlForTest.length === 0) { - setProxyIPv6SupportMap({}) - - return - } - - const newLatencyMap = await proxyGroupLatencyTestAPI( - proxyGroupName, - urlForTest, - latencyTestTimeoutDuration(), - ) - const newSupportMap = Object.fromEntries( - Object.entries(newLatencyMap).map(([k, v]) => [k, v > 0]), - ) - setProxyIPv6SupportMap((supportMap) => ({ - ...supportMap, - ...newSupportMap, - })) - } - const proxyLatencyTest = async (proxyName: string, provider: string) => { - await proxyIPv6SupportTest(proxyName, provider) setProxyLatencyTestingMap(proxyName, async () => { + await proxyIPv6SupportTest(proxyName, provider) const { delay } = await proxyLatencyTestAPI( proxyName, provider, @@ -273,19 +202,13 @@ export const useProxies = () => { } const proxyGroupLatencyTest = async (proxyGroupName: string) => { - await proxyGroupIPv6SupportTest(proxyGroupName) setProxyGroupLatencyTestingMap(proxyGroupName, async () => { - const newLatencyMap = await proxyGroupLatencyTestAPI( + await proxyGroupIPv6SupportTest(proxyGroupName) + await proxyGroupLatencyTestAPI( proxyGroupName, urlForLatencyTest(), latencyTestTimeoutDuration(), ) - - setLatencyMap((latencyMap) => ({ - ...latencyMap, - ...newLatencyMap, - })) - await fetchProxies() }) } @@ -320,8 +243,21 @@ export const useProxies = () => { await fetchProxies() }) + const getNowProxyNodeName = (name: string) => { + let node = proxyNodeMap()[name] + + if (!name || !node) { + return name + } + + while (node.now && node.now !== node.name) { + node = proxyNodeMap()[node.now] + } + + return node.name + } + return { - proxyIPv6SupportMap, proxyLatencyTestingMap, proxyGroupLatencyTestingMap, proxyProviderLatencyTestingMap, @@ -339,5 +275,6 @@ export const useProxies = () => { updateProviderByProviderName, updateAllProvider, proxyProviderLatencyTest, + getNowProxyNodeName, } }