metacubexd/src/signals/proxies.ts

161 lines
4.2 KiB
TypeScript
Raw Normal View History

2023-09-17 03:09:56 +08:00
import { batch, createSignal, untrack } from 'solid-js'
2023-09-12 21:33:16 +08:00
import {
closeSingleConnectionAPI,
fetchProxiesAPI,
fetchProxyProvidersAPI,
proxyGroupLatencyTestAPI,
proxyProviderHealthCheck,
selectProxyInGroupAPI,
updateProxyProviderAPI,
} from '~/apis'
2023-09-06 11:17:00 +08:00
import {
autoCloseConns,
2023-09-17 03:09:56 +08:00
latencyQualityMap,
latencyTestTimeoutDuration,
latestConnectionMsg,
restructRawMsgToConnection,
2023-09-12 21:33:16 +08:00
urlForLatencyTest,
} from '~/signals'
import type { Proxy, ProxyNode, ProxyProvider } from '~/types'
2023-08-29 20:20:01 +08:00
type ProxyInfo = {
name: string
udp: boolean
now: string
xudp: boolean
type: string
}
2023-08-30 23:02:55 +08:00
// these signals should be global state
const [proxies, setProxies] = createSignal<Proxy[]>([])
const [proxyProviders, setProxyProviders] = createSignal<ProxyProvider[]>([])
const [latencyMap, setLatencyMap] = createSignal<Record<string, number>>({})
const [proxyNodeMap, setProxyNodeMap] = createSignal<Record<string, ProxyInfo>>(
{},
)
2023-08-30 23:54:49 +08:00
const setProxiesInfo = (proxies: (Proxy | ProxyNode)[]) => {
const newProxyNodeMap = { ...proxyNodeMap() }
const newLatencyMap = { ...latencyMap() }
proxies.forEach((proxy) => {
2023-09-17 03:09:56 +08:00
const latency =
proxy.history.at(-1)?.delay || latencyQualityMap().NOT_CONNECTED
newProxyNodeMap[proxy.name] = {
udp: proxy.udp,
xudp: proxy.xudp,
type: proxy.type,
now: proxy.now,
name: proxy.name,
}
newLatencyMap[proxy.name] = latency
})
2023-09-17 03:09:56 +08:00
batch(() => {
setProxyNodeMap(newProxyNodeMap)
setLatencyMap(newLatencyMap)
})
}
export const useProxies = () => {
const updateProxies = async () => {
const [{ providers }, { proxies }] = await Promise.all([
2023-09-12 21:33:16 +08:00
fetchProxyProvidersAPI(),
fetchProxiesAPI(),
])
2023-08-29 20:20:01 +08:00
2023-09-01 10:45:38 +08:00
const sortIndex = [...(proxies['GLOBAL'].all ?? []), 'GLOBAL']
const sortedProxies = Object.values(proxies)
.filter((proxy) => proxy.all?.length)
.sort(
(prev, next) =>
sortIndex.indexOf(prev.name) - sortIndex.indexOf(next.name),
)
const sortedProviders = Object.values(providers).filter(
(provider) =>
provider.name !== 'default' && provider.vehicleType !== 'Compatible',
2023-08-29 20:20:01 +08:00
)
const allProxies: (Proxy | ProxyNode)[] = [
...Object.values(proxies),
...sortedProviders.flatMap((provider) => provider.proxies),
]
2023-09-17 03:09:56 +08:00
batch(() => {
setProxies(sortedProxies)
setProxyProviders(sortedProviders)
setProxiesInfo(allProxies)
})
2023-08-29 20:20:01 +08:00
}
2023-09-17 14:55:03 +08:00
const selectProxyInGroup = async (proxy: Proxy, proxyName: string) => {
2023-09-12 21:33:16 +08:00
await selectProxyInGroupAPI(proxy.name, proxyName)
2023-09-17 14:55:03 +08:00
await updateProxies()
if (autoCloseConns()) {
2023-09-12 21:33:16 +08:00
// we don't use activeConns from useConnection here for better performance,
// and we use empty array to restruct msg because they are closed, they won't have speed anyway
2023-09-08 15:45:15 +08:00
untrack(() => {
const activeConns = restructRawMsgToConnection(
latestConnectionMsg()?.connections ?? [],
[],
)
if (activeConns.length > 0) {
activeConns.forEach(({ id, chains }) => {
if (chains.includes(proxy.name)) {
2023-09-12 21:33:16 +08:00
closeSingleConnectionAPI(id)
2023-09-08 15:45:15 +08:00
}
})
}
})
}
2023-08-29 20:20:01 +08:00
}
2023-09-03 05:40:39 +08:00
const latencyTestByProxyGroupName = async (proxyGroupName: string) => {
2023-09-12 21:33:16 +08:00
const data = await proxyGroupLatencyTestAPI(
proxyGroupName,
urlForLatencyTest(),
latencyTestTimeoutDuration(),
)
2023-08-30 11:01:19 +08:00
setLatencyMap({
...latencyMap(),
...data,
})
2023-08-31 12:02:23 +08:00
}
2023-08-30 11:01:19 +08:00
2023-09-12 21:33:16 +08:00
const updateProviderByProviderName = async (providerName: string) => {
try {
2023-09-12 21:33:16 +08:00
await updateProxyProviderAPI(providerName)
} catch {}
await updateProxies()
2023-08-30 11:01:19 +08:00
}
2023-09-02 17:01:59 +08:00
const updateAllProvider = async () => {
await Promise.allSettled(
2023-09-12 21:33:16 +08:00
proxyProviders().map((provider) => updateProxyProviderAPI(provider.name)),
2023-09-02 17:01:59 +08:00
)
await updateProxies()
2023-09-02 17:01:59 +08:00
}
2023-08-31 12:02:23 +08:00
const healthCheckByProviderName = async (providerName: string) => {
2023-09-12 21:33:16 +08:00
await proxyProviderHealthCheck(providerName)
await updateProxies()
}
2023-08-29 20:20:01 +08:00
return {
proxies,
proxyProviders,
2023-09-03 05:40:39 +08:00
latencyTestByProxyGroupName,
latencyMap,
2023-08-30 23:54:49 +08:00
proxyNodeMap,
updateProxies,
2023-09-17 14:55:03 +08:00
selectProxyInGroup,
2023-08-31 12:02:23 +08:00
updateProviderByProviderName,
2023-09-02 17:01:59 +08:00
updateAllProvider,
2023-08-31 12:02:23 +08:00
healthCheckByProviderName,
2023-08-29 20:20:01 +08:00
}
}