mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-11-13 06:05:34 +08:00
feat(proxies): sortProxiesByOrderingType
This commit is contained in:
parent
c9ec575437
commit
635b8ba966
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -3,6 +3,7 @@
|
||||
"class",
|
||||
"className",
|
||||
"ngClass",
|
||||
"classList",
|
||||
".*ClassName*"
|
||||
]
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
"daisyui": "^3.6.4",
|
||||
"dayjs": "^1.11.9",
|
||||
"husky": "^8.0.3",
|
||||
"immer": "^10.0.2",
|
||||
"is-ip": "^5.0.1",
|
||||
"ky": "^1.0.0",
|
||||
"lint-staged": "^14.0.1",
|
||||
|
@ -83,6 +83,9 @@ dependencies:
|
||||
husky:
|
||||
specifier: ^8.0.3
|
||||
version: 8.0.3
|
||||
immer:
|
||||
specifier: ^10.0.2
|
||||
version: 10.0.2
|
||||
is-ip:
|
||||
specifier: ^5.0.1
|
||||
version: 5.0.1
|
||||
@ -4438,6 +4441,13 @@ packages:
|
||||
engines: { node: '>= 4' }
|
||||
dev: false
|
||||
|
||||
/immer@10.0.2:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==,
|
||||
}
|
||||
dev: false
|
||||
|
||||
/import-fresh@3.3.0:
|
||||
resolution:
|
||||
{
|
||||
|
@ -26,11 +26,11 @@ export const App = () => {
|
||||
|
||||
createEffect(() => {
|
||||
if (selectedEndpoint() && endpoint()) {
|
||||
useProxies().updateProxy()
|
||||
useProxies().updateProxies()
|
||||
}
|
||||
})
|
||||
|
||||
onMount(async () => {
|
||||
onMount(() => {
|
||||
if (!selectedEndpoint()) {
|
||||
navigate('/setup')
|
||||
}
|
||||
|
@ -1,20 +1,22 @@
|
||||
import { useI18n } from '@solid-primitives/i18n'
|
||||
import { Show, createEffect, createMemo, createSignal } from 'solid-js'
|
||||
import { LATENCY_QUALITY_MAP_HTTP } from '~/constants'
|
||||
import { latencyQualityMap, useProxies } from '~/signals'
|
||||
|
||||
export const Latency = (props: { name?: string }) => {
|
||||
const { delayMap } = useProxies()
|
||||
const [t] = useI18n()
|
||||
const { latencyMap } = useProxies()
|
||||
const [textClassName, setTextClassName] = createSignal('')
|
||||
const delay = createMemo(() => {
|
||||
return delayMap()[props.name!]
|
||||
const latency = createMemo(() => {
|
||||
return latencyMap()[props.name!]
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
setTextClassName('text-success')
|
||||
|
||||
if (delay() > latencyQualityMap().HIGH) {
|
||||
if (latency() > latencyQualityMap().HIGH) {
|
||||
setTextClassName('text-error')
|
||||
} else if (delay() > latencyQualityMap().MEDIUM) {
|
||||
} else if (latency() > latencyQualityMap().MEDIUM) {
|
||||
setTextClassName('text-warning')
|
||||
}
|
||||
})
|
||||
@ -23,11 +25,14 @@ export const Latency = (props: { name?: string }) => {
|
||||
<>
|
||||
<Show
|
||||
when={
|
||||
typeof delay() === 'number' &&
|
||||
delay() !== LATENCY_QUALITY_MAP_HTTP.NOT_CONNECTED
|
||||
typeof latency() === 'number' &&
|
||||
latency() !== LATENCY_QUALITY_MAP_HTTP.NOT_CONNECTED
|
||||
}
|
||||
>
|
||||
<span class={textClassName()}>{delay()}ms</span>
|
||||
<span class={`whitespace-nowrap ${textClassName()}`}>
|
||||
{latency()}
|
||||
{t('ms')}
|
||||
</span>
|
||||
</Show>
|
||||
</>
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import InfiniteScroll from 'solid-infinite-scroll'
|
||||
import { createMemo, createSignal } from 'solid-js'
|
||||
import ProxyNodeCard from './ProxyNodeCard'
|
||||
import { ProxyNodeCard } from '~/components'
|
||||
|
||||
export const ProxyCardGroups = (props: {
|
||||
proxies: string[]
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { createMemo } from 'solid-js'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { Latency } from '~/components'
|
||||
import { formatProxyType } from '~/helpers'
|
||||
import { useProxies } from '~/signals'
|
||||
|
||||
export default (props: {
|
||||
export const ProxyNodeCard = (props: {
|
||||
proxyName: string
|
||||
isSelected?: boolean
|
||||
onClick?: () => void
|
||||
@ -12,16 +13,6 @@ export default (props: {
|
||||
const { proxyNodeMap } = useProxies()
|
||||
const proxyNode = createMemo(() => proxyNodeMap()[proxyName])
|
||||
|
||||
const formatProxyType = (type = '') => {
|
||||
const t = type.toLowerCase()
|
||||
|
||||
if (t.includes('shadowsocks')) {
|
||||
return t.replace('shadowsocks', 'ss')
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={twMerge(
|
||||
|
@ -6,9 +6,9 @@ export const ProxyPreviewBar = (props: {
|
||||
proxyNameList: string[]
|
||||
now?: string
|
||||
}) => {
|
||||
const { delayMap } = useProxies()
|
||||
const { latencyMap } = useProxies()
|
||||
const delayList = createMemo(() =>
|
||||
props.proxyNameList.map((i) => delayMap()[i]),
|
||||
props.proxyNameList.map((i) => latencyMap()[i]),
|
||||
)
|
||||
const all = createMemo(() => delayList().length)
|
||||
const good = createMemo(
|
||||
|
@ -1,27 +1,22 @@
|
||||
import { For } from 'solid-js'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import {
|
||||
LATENCY_QUALITY_MAP_HTTP,
|
||||
LATENCY_QUALITY_MAP_HTTPS,
|
||||
} from '~/constants'
|
||||
import { isLatencyTestByHttps, useProxies } from '~/signals'
|
||||
import { latencyQualityMap, useProxies } from '~/signals'
|
||||
|
||||
const DelayDots = (p: { delay: number | undefined; selected: boolean }) => {
|
||||
const delayMap = isLatencyTestByHttps()
|
||||
? LATENCY_QUALITY_MAP_HTTP
|
||||
: LATENCY_QUALITY_MAP_HTTPS
|
||||
|
||||
let dotClassName = p.selected
|
||||
? 'bg-white border-4 border-success'
|
||||
: 'bg-success'
|
||||
|
||||
if (typeof p.delay !== 'number' || p.delay === delayMap.NOT_CONNECTED) {
|
||||
if (
|
||||
typeof p.delay !== 'number' ||
|
||||
p.delay === latencyQualityMap().NOT_CONNECTED
|
||||
) {
|
||||
dotClassName = p.selected
|
||||
? 'bg-white border-4 border-neutral'
|
||||
: 'bg-neutral'
|
||||
} else if (p.delay > delayMap.HIGH) {
|
||||
} else if (p.delay > latencyQualityMap().HIGH) {
|
||||
dotClassName = p.selected ? 'bg-white border-4 border-error' : 'bg-error'
|
||||
} else if (p.delay > delayMap.MEDIUM) {
|
||||
} else if (p.delay > latencyQualityMap().MEDIUM) {
|
||||
dotClassName = p.selected
|
||||
? 'bg-white border-4 border-warning'
|
||||
: 'bg-warning'
|
||||
@ -34,14 +29,14 @@ export const ProxyPreviewDots = (props: {
|
||||
proxyNameList: string[]
|
||||
now?: string
|
||||
}) => {
|
||||
const { delayMap } = useProxies()
|
||||
const { latencyMap } = useProxies()
|
||||
|
||||
return (
|
||||
<div class="flex w-full flex-wrap items-center">
|
||||
<For
|
||||
each={props.proxyNameList.map((name): [string, number] => [
|
||||
name,
|
||||
delayMap()[name],
|
||||
latencyMap()[name],
|
||||
])}
|
||||
>
|
||||
{([name, delay]) => {
|
||||
|
@ -41,13 +41,13 @@ export enum ROUTES {
|
||||
}
|
||||
|
||||
export enum LATENCY_QUALITY_MAP_HTTP {
|
||||
NOT_CONNECTED = 0,
|
||||
NOT_CONNECTED = -1,
|
||||
MEDIUM = 200,
|
||||
HIGH = 500,
|
||||
}
|
||||
|
||||
export enum LATENCY_QUALITY_MAP_HTTPS {
|
||||
NOT_CONNECTED = 0,
|
||||
NOT_CONNECTED = -1,
|
||||
MEDIUM = 800,
|
||||
HIGH = 1500,
|
||||
}
|
||||
@ -59,7 +59,7 @@ export enum PROXIES_PREVIEW_TYPE {
|
||||
Auto = 'auto',
|
||||
}
|
||||
|
||||
export enum PROXIES_SORTING_TYPE {
|
||||
export enum PROXIES_ORDERING_TYPE {
|
||||
NATURAL = 'orderNatural',
|
||||
LATENCY_ASC = 'orderLatency_asc',
|
||||
LATENCY_DESC = 'orderLatency_desc',
|
||||
|
@ -1,7 +1,5 @@
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
import { PROXIES_ORDERING_TYPE } from '~/constants'
|
||||
|
||||
export const formatTimeFromNow = (time: number | string) => {
|
||||
return dayjs(time).fromNow()
|
||||
@ -16,3 +14,45 @@ export const getBtnElFromClickEvent = (event: MouseEvent) => {
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
export const formatProxyType = (type = '') => {
|
||||
const t = type.toLowerCase()
|
||||
|
||||
if (t.includes('shadowsocks')) {
|
||||
return t.replace('shadowsocks', 'ss')
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
export const sortProxiesByOrderingType = (
|
||||
proxyNames: string[],
|
||||
proxyLatencyMap: Record<string, number>,
|
||||
orderingType: PROXIES_ORDERING_TYPE,
|
||||
) => {
|
||||
if (orderingType === PROXIES_ORDERING_TYPE.NATURAL) {
|
||||
return proxyNames
|
||||
}
|
||||
|
||||
return proxyNames.sort((a, b) => {
|
||||
const prevLatency = proxyLatencyMap[a]
|
||||
const nextLatency = proxyLatencyMap[b]
|
||||
|
||||
switch (orderingType) {
|
||||
case PROXIES_ORDERING_TYPE.LATENCY_ASC:
|
||||
if (prevLatency === -1) return 1
|
||||
if (nextLatency === -1) return -1
|
||||
return prevLatency - nextLatency
|
||||
case PROXIES_ORDERING_TYPE.LATENCY_DESC:
|
||||
if (prevLatency === -1) return 1
|
||||
if (nextLatency === -1) return -1
|
||||
return nextLatency - prevLatency
|
||||
case PROXIES_ORDERING_TYPE.NAME_ASC:
|
||||
return a.localeCompare(b)
|
||||
case PROXIES_ORDERING_TYPE.NAME_DESC:
|
||||
return b.localeCompare(a)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -54,4 +54,5 @@ export default {
|
||||
orderLatency_desc: 'By latency from high to low',
|
||||
orderName_asc: 'By name alphabetically (A-Z)',
|
||||
orderName_desc: 'By name alphabetically (Z-A)',
|
||||
ms: 'ms',
|
||||
}
|
||||
|
@ -54,4 +54,5 @@ export default {
|
||||
orderLatency_desc: '按延迟从高到低',
|
||||
orderName_asc: '按名称字母排序 (A-Z)',
|
||||
orderName_desc: '按名称字母排序 (Z-A)',
|
||||
ms: '毫秒',
|
||||
}
|
||||
|
@ -2,11 +2,13 @@
|
||||
import '~/index.css'
|
||||
|
||||
import { Router, hashIntegration } from '@solidjs/router'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { render } from 'solid-js/web'
|
||||
import { App } from '~/App'
|
||||
import { I18nProvider } from '~/i18n'
|
||||
|
||||
const root = document.getElementById('root')
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
render(
|
||||
() => (
|
||||
@ -16,5 +18,5 @@ render(
|
||||
</Router>
|
||||
</I18nProvider>
|
||||
),
|
||||
root!,
|
||||
document.getElementById('root')!,
|
||||
)
|
||||
|
@ -4,22 +4,26 @@ import { useI18n } from '@solid-primitives/i18n'
|
||||
import { For, Show, createSignal, onMount } from 'solid-js'
|
||||
import { z } from 'zod'
|
||||
import { Button } from '~/components'
|
||||
import { PROXIES_PREVIEW_TYPE, PROXIES_SORTING_TYPE, themes } from '~/constants'
|
||||
import {
|
||||
PROXIES_ORDERING_TYPE,
|
||||
PROXIES_PREVIEW_TYPE,
|
||||
themes,
|
||||
} from '~/constants'
|
||||
import {
|
||||
applyThemeByMode,
|
||||
autoCloseConns,
|
||||
autoSwitchTheme,
|
||||
favDayTheme,
|
||||
favNightTheme,
|
||||
proxiesOrderingType,
|
||||
proxiesPreviewType,
|
||||
proxiesSortingType,
|
||||
renderInTwoColumn,
|
||||
setAutoCloseConns,
|
||||
setAutoSwitchTheme,
|
||||
setFavDayTheme,
|
||||
setFavNightTheme,
|
||||
setProxiesOrderingType,
|
||||
setProxiesPreviewType,
|
||||
setProxiesSortingType,
|
||||
setRenderInTwoColumn,
|
||||
setUrlForDelayTest,
|
||||
urlForDelayTest,
|
||||
@ -289,7 +293,7 @@ const ConfigForXd = () => {
|
||||
<div class="pb-4">{t('proxiesSorting')}</div>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<For each={Object.values(PROXIES_SORTING_TYPE)}>
|
||||
<For each={Object.values(PROXIES_ORDERING_TYPE)}>
|
||||
{(value) => (
|
||||
<label class="flex items-center gap-2">
|
||||
<span>{t(value)}</span>
|
||||
@ -298,8 +302,8 @@ const ConfigForXd = () => {
|
||||
class="radio"
|
||||
aria-label={value}
|
||||
type="radio"
|
||||
checked={value === proxiesSortingType()}
|
||||
onChange={() => setProxiesSortingType(value)}
|
||||
checked={value === proxiesOrderingType()}
|
||||
onChange={() => setProxiesOrderingType(value)}
|
||||
/>
|
||||
</label>
|
||||
)}
|
||||
|
@ -8,14 +8,18 @@ import {
|
||||
ProxyCardGroups,
|
||||
ProxyNodePreview,
|
||||
} from '~/components'
|
||||
import { getBtnElFromClickEvent } from '~/helpers'
|
||||
import { useProxies } from '~/signals'
|
||||
import { getBtnElFromClickEvent, sortProxiesByOrderingType } from '~/helpers'
|
||||
import { proxiesOrderingType, useProxies } from '~/signals'
|
||||
import type { Proxy } from '~/types'
|
||||
|
||||
export default () => {
|
||||
const [t] = useI18n()
|
||||
const { proxies, setProxyGroupByProxyName, delayTestByProxyGroupName } =
|
||||
useProxies()
|
||||
const {
|
||||
proxies,
|
||||
setProxyGroupByProxyName,
|
||||
delayTestByProxyGroupName,
|
||||
latencyMap,
|
||||
} = useProxies()
|
||||
|
||||
const [collapsedMap, setCollapsedMap] = createSignal<Record<string, boolean>>(
|
||||
{},
|
||||
@ -66,7 +70,11 @@ export default () => {
|
||||
|
||||
const content = (
|
||||
<ProxyCardGroups
|
||||
proxies={proxy.all!}
|
||||
proxies={sortProxiesByOrderingType(
|
||||
proxy.all ?? [],
|
||||
latencyMap(),
|
||||
proxiesOrderingType(),
|
||||
)}
|
||||
now={proxy.now}
|
||||
onClick={(name) => {
|
||||
onProxyNodeClick(proxy, name)
|
||||
|
@ -3,8 +3,8 @@ import { createSignal } from 'solid-js'
|
||||
import {
|
||||
LATENCY_QUALITY_MAP_HTTP,
|
||||
LATENCY_QUALITY_MAP_HTTPS,
|
||||
PROXIES_ORDERING_TYPE,
|
||||
PROXIES_PREVIEW_TYPE,
|
||||
PROXIES_SORTING_TYPE,
|
||||
} from '~/constants'
|
||||
import { setCurTheme } from '~/signals'
|
||||
|
||||
@ -12,9 +12,9 @@ export const [proxiesPreviewType, setProxiesPreviewType] = makePersisted(
|
||||
createSignal(PROXIES_PREVIEW_TYPE.Auto),
|
||||
{ name: 'proxiesPreviewType', storage: localStorage },
|
||||
)
|
||||
export const [proxiesSortingType, setProxiesSortingType] = makePersisted(
|
||||
createSignal(PROXIES_SORTING_TYPE.NATURAL),
|
||||
{ name: 'proxiesSortingType', storage: localStorage },
|
||||
export const [proxiesOrderingType, setProxiesOrderingType] = makePersisted(
|
||||
createSignal(PROXIES_ORDERING_TYPE.NATURAL),
|
||||
{ name: 'proxiesOrderingType', storage: localStorage },
|
||||
)
|
||||
export const [urlForDelayTest, setUrlForDelayTest] = makePersisted(
|
||||
createSignal('https://www.gstatic.com/generate_204'),
|
||||
|
@ -11,7 +11,7 @@ type ProxyInfo = {
|
||||
const [proxies, setProxies] = createSignal<Proxy[]>([])
|
||||
const [proxyProviders, setProxyProviders] = createSignal<ProxyProvider[]>([])
|
||||
|
||||
const [delayMap, setDelayMap] = createSignal<Record<string, number>>({})
|
||||
const [latencyMap, setLatencyMap] = createSignal<Record<string, number>>({})
|
||||
const [proxyNodeMap, setProxyNodeMap] = createSignal<Record<string, ProxyInfo>>(
|
||||
{},
|
||||
)
|
||||
@ -21,7 +21,7 @@ export const useProxies = () => {
|
||||
|
||||
const setProxyInfoByProixes = (proxies: Proxy[] | ProxyNode[]) => {
|
||||
proxies.forEach((proxy) => {
|
||||
const delay = proxy.history.at(-1)?.delay ?? 0
|
||||
const delay = proxy.history.at(-1)?.delay ?? -1
|
||||
|
||||
setProxyNodeMap({
|
||||
...proxyNodeMap(),
|
||||
@ -31,14 +31,14 @@ export const useProxies = () => {
|
||||
name: proxy.name,
|
||||
},
|
||||
})
|
||||
setDelayMap({
|
||||
...delayMap(),
|
||||
setLatencyMap({
|
||||
...latencyMap(),
|
||||
[proxy.name]: delay,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const updateProxy = async () => {
|
||||
const updateProxies = async () => {
|
||||
const { providers } = await request
|
||||
.get('providers/proxies')
|
||||
.json<{ providers: Record<string, ProxyProvider> }>()
|
||||
@ -58,14 +58,15 @@ export const useProxies = () => {
|
||||
.get('proxies')
|
||||
.json<{ proxies: Record<string, Proxy> }>()
|
||||
const sortIndex = [...(proxies['GLOBAL'].all ?? []), 'GLOBAL']
|
||||
const proxiesArray = Object.values(proxies)
|
||||
|
||||
setProxyInfoByProixes(Object.values(proxies))
|
||||
setProxyInfoByProixes(proxiesArray)
|
||||
setProxies(
|
||||
Object.values(proxies)
|
||||
proxiesArray
|
||||
.filter((proxy) => proxy.all?.length)
|
||||
.sort(
|
||||
(pre, next) =>
|
||||
sortIndex.indexOf(pre.name) - sortIndex.indexOf(next.name),
|
||||
(prev, next) =>
|
||||
sortIndex.indexOf(prev.name) - sortIndex.indexOf(next.name),
|
||||
),
|
||||
)
|
||||
}
|
||||
@ -97,8 +98,8 @@ export const useProxies = () => {
|
||||
})
|
||||
.json()
|
||||
|
||||
setDelayMap({
|
||||
...delayMap(),
|
||||
setLatencyMap({
|
||||
...latencyMap(),
|
||||
...data,
|
||||
})
|
||||
}
|
||||
@ -107,7 +108,7 @@ export const useProxies = () => {
|
||||
try {
|
||||
await request.put(`providers/proxies/${proxyProviderName}`)
|
||||
} catch {}
|
||||
await updateProxy()
|
||||
await updateProxies()
|
||||
}
|
||||
|
||||
const updateAllProvider = async () => {
|
||||
@ -116,23 +117,23 @@ export const useProxies = () => {
|
||||
return request.put(`providers/proxies/${provider.name}`)
|
||||
}),
|
||||
)
|
||||
await updateProxy()
|
||||
await updateProxies()
|
||||
}
|
||||
|
||||
const healthCheckByProviderName = async (providerName: string) => {
|
||||
await request.get(`providers/proxies/${providerName}/healthcheck`, {
|
||||
timeout: 30 * 1000, // thie api is a little bit slow sometimes...
|
||||
})
|
||||
await updateProxy()
|
||||
await updateProxies()
|
||||
}
|
||||
|
||||
return {
|
||||
proxies,
|
||||
proxyProviders,
|
||||
delayTestByProxyGroupName,
|
||||
delayMap,
|
||||
latencyMap,
|
||||
proxyNodeMap,
|
||||
updateProxy,
|
||||
updateProxies,
|
||||
setProxyGroupByProxyName,
|
||||
updateProviderByProviderName,
|
||||
updateAllProvider,
|
||||
|
Loading…
Reference in New Issue
Block a user