feat: add support for IPv6 check (#403)

* feat: add support for IPv6 check

* Update src/i18n/en.ts

Co-authored-by: kunish <17328586+kunish@users.noreply.github.com>
Signed-off-by: ak <140048181+arkxfly@users.noreply.github.com>

* Update src/i18n/zh.ts

Co-authored-by: kunish <17328586+kunish@users.noreply.github.com>
Signed-off-by: ak <140048181+arkxfly@users.noreply.github.com>

---------

Signed-off-by: ak <140048181+arkxfly@users.noreply.github.com>
Co-authored-by: kunish <17328586+kunish@users.noreply.github.com>
This commit is contained in:
ak 2023-10-22 13:00:09 +08:00 committed by GitHub
parent f5509c0290
commit 4d5543c64b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 142 additions and 22 deletions

View File

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

View File

@ -15,6 +15,8 @@ import {
setProxiesOrderingType, setProxiesOrderingType,
setProxiesPreviewType, setProxiesPreviewType,
setUrlForLatencyTest, setUrlForLatencyTest,
setUrlIPv6SupportTest,
urlForIPv6SupportTest,
urlForLatencyTest, urlForLatencyTest,
} from '~/signals' } from '~/signals'
@ -68,6 +70,16 @@ export const ProxiesSettingsModal: Component<{
/> />
</div> </div>
<div class="flex flex-col">
<ConfigTitle withDivider>{t('urlForIPv6SupportTest')}</ConfigTitle>
<input
class="input input-bordered w-full"
value={urlForIPv6SupportTest()}
onChange={(e) => setUrlIPv6SupportTest(e.target.value?.trim())}
/>
</div>
<div> <div>
<ConfigTitle withDivider>{t('proxiesSorting')}</ConfigTitle> <ConfigTitle withDivider>{t('proxiesSorting')}</ConfigTitle>

View File

@ -1,7 +1,7 @@
import { IconBrandSpeedtest } from '@tabler/icons-solidjs' import { IconBrandSpeedtest } from '@tabler/icons-solidjs'
import { createMemo, Show } from 'solid-js' import { createMemo, Show } from 'solid-js'
import { twMerge } from 'tailwind-merge' import { twMerge } from 'tailwind-merge'
import { Button, Latency } from '~/components' import { Button, IPv6Support, Latency } from '~/components'
import { filterSpecialProxyType, formatProxyType } from '~/helpers' import { filterSpecialProxyType, formatProxyType } from '~/helpers'
import { useProxies } from '~/signals' import { useProxies } from '~/signals'
@ -36,23 +36,26 @@ export const ProxyNodeCard = (props: {
<div class="flex items-center justify-between gap-2"> <div class="flex items-center justify-between gap-2">
<span class="text-left text-sm">{proxyName}</span> <span class="text-left text-sm">{proxyName}</span>
<Button <span class="flex items-center gap-1">
class="btn-circle btn-ghost h-auto min-h-0 w-auto" <IPv6Support name={props.proxyName} />
icon={ <Button
<IconBrandSpeedtest class="btn-circle btn-ghost h-auto min-h-0 w-auto"
size={20} icon={
class={twMerge( <IconBrandSpeedtest
proxyLatencyTestingMap()[proxyName] && size={20}
'animate-pulse text-success', class={twMerge(
)} proxyLatencyTestingMap()[proxyName] &&
/> 'animate-pulse text-success',
} )}
onClick={(e) => { />
e.stopPropagation() }
onClick={(e) => {
e.stopPropagation()
void proxyLatencyTest(proxyName, proxyNode().provider) void proxyLatencyTest(proxyName, proxyNode().provider)
}} }}
/> />
</span>
</div> </div>
<div class="flex items-center justify-between gap-1"> <div class="flex items-center justify-between gap-1">

View File

@ -4,6 +4,7 @@ export * from './ConfigTitle'
export * from './ConnectionsSettingsModal' export * from './ConnectionsSettingsModal'
export * from './ConnectionsTableDetailsModal' export * from './ConnectionsTableDetailsModal'
export * from './Header' export * from './Header'
export * from './IPv6Support'
export * from './Latency' export * from './Latency'
export * from './LogoText' export * from './LogoText'
export * from './LogsSettingsModal' export * from './LogsSettingsModal'

View File

@ -46,6 +46,7 @@ export default {
auto: 'Auto', auto: 'Auto',
off: 'Off', off: 'Off',
proxiesPreviewType: 'Proxies preview type', proxiesPreviewType: 'Proxies preview type',
urlForIPv6SupportTest: 'URL for IPv6 support test',
urlForLatencyTest: 'URL for latency test', urlForLatencyTest: 'URL for latency test',
autoCloseConns: 'Automatically Close connections', autoCloseConns: 'Automatically Close connections',
useTwemoji: 'Use Twemoji Mozilla Font', useTwemoji: 'Use Twemoji Mozilla Font',

View File

@ -48,6 +48,7 @@ export default {
auto: '自适应', auto: '自适应',
off: '关闭', off: '关闭',
proxiesPreviewType: '节点组预览样式', proxiesPreviewType: '节点组预览样式',
urlForIPv6SupportTest: '测试 IPv6 支持链接',
urlForLatencyTest: '测速链接', urlForLatencyTest: '测速链接',
autoCloseConns: '自动断开连接', autoCloseConns: '自动断开连接',
useTwemoji: '使用 Twemoji Mozilla 字体', useTwemoji: '使用 Twemoji Mozilla 字体',

View File

@ -36,6 +36,12 @@ export const [urlForLatencyTest, setUrlForLatencyTest] = makePersisted(
createSignal('https://www.gstatic.com/generate_204'), createSignal('https://www.gstatic.com/generate_204'),
{ name: 'urlForLatencyTest', storage: localStorage }, { name: 'urlForLatencyTest', storage: localStorage },
) )
export const [urlForIPv6SupportTest, setUrlIPv6SupportTest] = makePersisted(
createSignal('https://api-ipv6.ip.sb/ip'),
{ name: 'urlForIPv6SupportTest', storage: localStorage },
)
export const [autoCloseConns, setAutoCloseConns] = makePersisted( export const [autoCloseConns, setAutoCloseConns] = makePersisted(
createSignal(false), createSignal(false),
{ name: 'autoCloseConns', storage: localStorage }, { name: 'autoCloseConns', storage: localStorage },

View File

@ -16,6 +16,7 @@ import {
latencyTestTimeoutDuration, latencyTestTimeoutDuration,
latestConnectionMsg, latestConnectionMsg,
restructRawMsgToConnection, restructRawMsgToConnection,
urlForIPv6SupportTest,
urlForLatencyTest, urlForLatencyTest,
} from '~/signals' } from '~/signals'
import type { Proxy, ProxyNode, ProxyProvider } from '~/types' import type { Proxy, ProxyNode, ProxyProvider } from '~/types'
@ -56,6 +57,9 @@ 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>>(
{}, {},
) )
@ -65,20 +69,43 @@ const setProxiesInfo = (
) => { ) => {
const newProxyNodeMap = { ...proxyNodeMap() } const newProxyNodeMap = { ...proxyNodeMap() }
const newLatencyMap = { ...latencyMap() } const newLatencyMap = { ...latencyMap() }
const newProxyIPv6SupportMap = { ...proxyIPv6SupportMap() }
const lastDelay = (
proxy: Pick<Proxy, 'extra' | 'history'>,
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 || !fallbackDefault) {
return delay
}
}
return proxy.history?.at(-1)?.delay
}
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 }
const latency = const latency =
proxy.history.at(-1)?.delay || latencyQualityMap().NOT_CONNECTED lastDelay(proxy, urlForLatencyTest()) || latencyQualityMap().NOT_CONNECTED
newProxyNodeMap[proxy.name] = { udp, xudp, type, now, name, provider }
newLatencyMap[proxy.name] = latency newLatencyMap[proxy.name] = latency
const proxyIPv6Support =
(lastDelay(proxy, urlForIPv6SupportTest(), false) ?? 0) > 0
newProxyIPv6SupportMap[proxy.name] = proxyIPv6Support
}) })
batch(() => { batch(() => {
setProxyNodeMap(newProxyNodeMap) setProxyNodeMap(newProxyNodeMap)
setLatencyMap(newLatencyMap) setLatencyMap(newLatencyMap)
setProxyIPv6SupportMap(newProxyIPv6SupportMap)
}) })
} }
@ -144,7 +171,56 @@ export const useProxies = () => {
} }
} }
const proxyLatencyTest = (proxyName: string, provider: string) => 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) => {
setProxyLatencyTestingMap(proxyName, async () => { setProxyLatencyTestingMap(proxyName, async () => {
const { delay } = await proxyLatencyTestAPI( const { delay } = await proxyLatencyTestAPI(
proxyName, proxyName,
@ -158,8 +234,10 @@ export const useProxies = () => {
[proxyName]: delay, [proxyName]: delay,
})) }))
}) })
await proxyIPv6SupportTest(proxyName, provider)
}
const proxyGroupLatencyTest = (proxyGroupName: string) => const proxyGroupLatencyTest = async (proxyGroupName: string) => {
setProxyGroupLatencyTestingMap(proxyGroupName, async () => { setProxyGroupLatencyTestingMap(proxyGroupName, async () => {
const newLatencyMap = await proxyGroupLatencyTestAPI( const newLatencyMap = await proxyGroupLatencyTestAPI(
proxyGroupName, proxyGroupName,
@ -174,6 +252,8 @@ export const useProxies = () => {
await fetchProxies() await fetchProxies()
}) })
await proxyGroupIPv6SupportTest(proxyGroupName)
}
const updateProviderByProviderName = (providerName: string) => const updateProviderByProviderName = (providerName: string) =>
setUpdatingMap(providerName, async () => { setUpdatingMap(providerName, async () => {
@ -206,6 +286,7 @@ export const useProxies = () => {
return { return {
collapsedMap, collapsedMap,
setCollapsedMap, setCollapsedMap,
proxyIPv6SupportMap,
proxyLatencyTestingMap, proxyLatencyTestingMap,
proxyGroupLatencyTestingMap, proxyGroupLatencyTestingMap,
proxyProviderLatencyTestingMap, proxyProviderLatencyTestingMap,