fix: latency test for selector and ipv6 test (#860)

This commit is contained in:
YetAnotherZephyruso 2024-07-25 17:09:22 +08:00 committed by GitHub
parent e84b348a6e
commit 5da350d08e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 135 additions and 126 deletions

View File

@ -1,14 +1,16 @@
import { useProxies } from '~/signals' import { useProxies } from '~/signals'
import { proxyIPv6SupportMap } from '~/signals/ipv6'
export const IPv6Support = (props: { name?: string }) => { export const IPv6Support = (props: { name?: string; class?: string }) => {
const { proxyIPv6SupportMap } = useProxies() const { getNowProxyNodeName } = useProxies()
const support = createMemo(() => proxyIPv6SupportMap()[props.name!] === true)
const support = createMemo(() => {
return proxyIPv6SupportMap()[getNowProxyNodeName(props.name || '')]
})
return ( return (
<Show when={support()}> <Show when={support()}>
<span class="badge badge-sm p-px"> <span class={`scale-75 ${props.class}`}>IPv6</span>
<span class="scale-75">IPv6</span>
</span>
</Show> </Show>
) )
} }

View File

@ -4,9 +4,11 @@ import { latencyQualityMap, useProxies } from '~/signals'
export const Latency = (props: { name?: string; class?: string }) => { export const Latency = (props: { name?: string; class?: string }) => {
const [t] = useI18n() const [t] = useI18n()
const { latencyMap } = useProxies() const { getNowProxyNodeName, latencyMap } = useProxies()
const [textClassName, setTextClassName] = createSignal('') const [textClassName, setTextClassName] = createSignal('')
const latency = createMemo(() => latencyMap()[props.name!]) const latency = createMemo(() => {
return latencyMap()[getNowProxyNodeName(props.name || '')]
})
createEffect(() => { createEffect(() => {
setTextClassName('text-success') setTextClassName('text-success')

View File

@ -9,8 +9,10 @@ export type WsMsg = {
downloadTotal: number downloadTotal: number
} | null } | null
// DIRECT is from clash
// direct and dns-out is from the example of sing-box official site
export const [quickFilterRegex, setQuickFilterRegex] = makePersisted( export const [quickFilterRegex, setQuickFilterRegex] = makePersisted(
createSignal<string>('Direct|direct|dns-out'), createSignal<string>('DIRECT|direct|dns-out'),
{ {
name: 'quickFilterRegex', name: 'quickFilterRegex',
storage: localStorage, storage: localStorage,

66
src/signals/ipv6.ts Normal file
View File

@ -0,0 +1,66 @@
import { proxyGroupLatencyTestAPI, proxyLatencyTestAPI } from '~/apis'
import {
latencyQualityMap,
latencyTestTimeoutDuration,
urlForIPv6SupportTest,
} from './config'
export const [proxyIPv6SupportMap, setProxyIPv6SupportMap] = createSignal<
Record<string, boolean>
>({})
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,
}))
}

View File

@ -19,6 +19,12 @@ import {
urlForLatencyTest, urlForLatencyTest,
} from '~/signals' } from '~/signals'
import type { Proxy, ProxyNode, ProxyProvider } from '~/types' import type { Proxy, ProxyNode, ProxyProvider } from '~/types'
import {
proxyGroupIPv6SupportTest,
proxyIPv6SupportMap,
proxyIPv6SupportTest,
setProxyIPv6SupportMap,
} from './ipv6'
type ProxyInfo = { type ProxyInfo = {
name: string name: string
@ -58,25 +64,15 @@ const [proxyProviders, setProxyProviders] = createSignal<
>([]) >([])
const [latencyMap, setLatencyMap] = createSignal<Record<string, number>>({}) const [latencyMap, setLatencyMap] = createSignal<Record<string, number>>({})
const [proxyIPv6SupportMap, setProxyIPv6SupportMap] = createSignal<
Record<string, boolean>
>({})
const [proxyNodeMap, setProxyNodeMap] = createSignal<Record<string, ProxyInfo>>( const [proxyNodeMap, setProxyNodeMap] = createSignal<Record<string, ProxyInfo>>(
{}, {},
) )
const setProxiesInfo = ( const getLatencyFromProxy = (
proxies: (ProxyWithProvider | ProxyNodeWithProvider)[],
) => {
const newProxyNodeMap = { ...proxyNodeMap() }
const newLatencyMap = { ...latencyMap() }
const newProxyIPv6SupportMap = { ...proxyIPv6SupportMap() }
const lastDelay = (
proxy: Pick<Proxy, 'extra' | 'history'>, proxy: Pick<Proxy, 'extra' | 'history'>,
url: string, url: string,
fallbackDefault = true, fallbackDefault = true,
) => { ) => {
const extra = proxy.extra?.[url] as Proxy['history'] | undefined const extra = proxy.extra?.[url] as Proxy['history'] | undefined
if (Array.isArray(extra)) { if (Array.isArray(extra)) {
@ -88,52 +84,34 @@ const setProxiesInfo = (
} }
if (!fallbackDefault) { if (!fallbackDefault) {
return undefined return latencyQualityMap().NOT_CONNECTED
} }
return proxy.history?.at(-1)?.delay return proxy.history?.at(-1)?.delay ?? latencyQualityMap().NOT_CONNECTED
} }
const dependedLatencyProxies = {} as Record<string, Set<string>> const setProxiesInfo = (
proxies: (ProxyWithProvider | ProxyNodeWithProvider)[],
) => {
const newProxyNodeMap = { ...proxyNodeMap() }
const newLatencyMap = { ...latencyMap() }
const newProxyIPv6SupportMap = { ...proxyIPv6SupportMap() }
proxies.forEach((proxy) => { proxies.forEach((proxy) => {
const { udp, xudp, type, now, name, provider = '' } = proxy const { udp, xudp, type, now, name, provider = '' } = proxy
newProxyNodeMap[proxy.name] = { udp, xudp, type, now, name, provider } 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 // we don't set it when false because sing-box didn't have "extra" so it will always be false
// it seems that only clash.core and clash.premium have issues if (
if (!now) { getLatencyFromProxy(proxy, urlForIPv6SupportTest(), false) >
newLatencyMap[proxy.name] =
lastDelay(proxy, urlForLatencyTest()) ||
latencyQualityMap().NOT_CONNECTED latencyQualityMap().NOT_CONNECTED
} else if (newLatencyMap[now] !== undefined) { ) {
newLatencyMap[proxy.name] = newLatencyMap[now] newProxyIPv6SupportMap[proxy.name] = true
} else {
const dependencies = dependedLatencyProxies[now] ?? new Set()
dependencies.add(proxy.name)
dependedLatencyProxies[now] = dependencies
} }
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(() => { batch(() => {
setProxyNodeMap(newProxyNodeMap) setProxyNodeMap(newProxyNodeMap)
setLatencyMap(newLatencyMap) 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) => { const proxyLatencyTest = async (proxyName: string, provider: string) => {
await proxyIPv6SupportTest(proxyName, provider)
setProxyLatencyTestingMap(proxyName, async () => { setProxyLatencyTestingMap(proxyName, async () => {
await proxyIPv6SupportTest(proxyName, provider)
const { delay } = await proxyLatencyTestAPI( const { delay } = await proxyLatencyTestAPI(
proxyName, proxyName,
provider, provider,
@ -273,19 +202,13 @@ export const useProxies = () => {
} }
const proxyGroupLatencyTest = async (proxyGroupName: string) => { const proxyGroupLatencyTest = async (proxyGroupName: string) => {
await proxyGroupIPv6SupportTest(proxyGroupName)
setProxyGroupLatencyTestingMap(proxyGroupName, async () => { setProxyGroupLatencyTestingMap(proxyGroupName, async () => {
const newLatencyMap = await proxyGroupLatencyTestAPI( await proxyGroupIPv6SupportTest(proxyGroupName)
await proxyGroupLatencyTestAPI(
proxyGroupName, proxyGroupName,
urlForLatencyTest(), urlForLatencyTest(),
latencyTestTimeoutDuration(), latencyTestTimeoutDuration(),
) )
setLatencyMap((latencyMap) => ({
...latencyMap,
...newLatencyMap,
}))
await fetchProxies() await fetchProxies()
}) })
} }
@ -320,8 +243,21 @@ export const useProxies = () => {
await fetchProxies() 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 { return {
proxyIPv6SupportMap,
proxyLatencyTestingMap, proxyLatencyTestingMap,
proxyGroupLatencyTestingMap, proxyGroupLatencyTestingMap,
proxyProviderLatencyTestingMap, proxyProviderLatencyTestingMap,
@ -339,5 +275,6 @@ export const useProxies = () => {
updateProviderByProviderName, updateProviderByProviderName,
updateAllProvider, updateAllProvider,
proxyProviderLatencyTest, proxyProviderLatencyTest,
getNowProxyNodeName,
} }
} }