diff options
| author | Matain <[email protected]> | 2022-06-12 23:34:56 +0800 |
|---|---|---|
| committer | Matain <[email protected]> | 2022-06-12 23:34:56 +0800 |
| commit | ea5d7cf003eeef30cb7bbe789c6ba7f314bf1ce4 (patch) | |
| tree | bff1bd7b0e8e8eb753d373b57f007bbe97f96c76 /src/store | |
| parent | 4fd2c8f646e48dd0c07d0c2041de52e9a4f8bc82 (diff) | |
| parent | 38571da24ac54137564be5e41b7a409009e2ee10 (diff) | |
Merge branch 'master' of https://github.com/haishanh/yacd into haishanh-master
Diffstat (limited to 'src/store')
| -rw-r--r-- | src/store/app.ts | 4 | ||||
| -rw-r--r-- | src/store/proxies.tsx | 170 | ||||
| -rw-r--r-- | src/store/types.ts | 32 |
3 files changed, 96 insertions, 110 deletions
diff --git a/src/store/app.ts b/src/store/app.ts index 7262b32..2789981 100644 --- a/src/store/app.ts +++ b/src/store/app.ts @@ -152,7 +152,7 @@ export function updateCollapsibleIsOpen(prefix: string, name: string, v: boolean const defaultClashAPIConfig = { baseURL: document.getElementById('app')?.getAttribute('data-base-url') ?? 'http://127.0.0.1:9090', secret: '', - addedAt: 0 + addedAt: 0, }; // type Theme = 'light' | 'dark'; const defaultState: StateApp = { @@ -169,7 +169,7 @@ const defaultState: StateApp = { proxySortBy: 'Natural', hideUnavailableProxies: false, autoCloseOldConns: false, - logStreamingPaused: false + logStreamingPaused: false, }; function parseConfigQueryString() { diff --git a/src/store/proxies.tsx b/src/store/proxies.tsx index e06d16c..5f4c0aa 100644 --- a/src/store/proxies.tsx +++ b/src/store/proxies.tsx @@ -1,9 +1,10 @@ import { atom } from 'recoil'; -/* import { ProxyItem, ProxiesMapping, DelayMapping } from 'src/store/types'; */ import { + DelayMapping, DispatchFn, FormattedProxyProvider, GetStateFn, + LatencyHistory, ProxiesMapping, ProxyItem, ProxyProvider, @@ -35,10 +36,10 @@ const noop = () => null; export const NonProxyTypes = [ 'Direct', - 'Fallback', 'Reject', - 'Pass', + 'Relay', 'Selector', + 'Fallback', 'URLTest', 'LoadBalance', 'Unknown', @@ -49,8 +50,20 @@ export const getDelay = (s: State) => s.proxies.delay; export const getProxyGroupNames = (s: State) => s.proxies.groupNames; export const getProxyProviders = (s: State) => s.proxies.proxyProviders || []; export const getDangleProxyNames = (s: State) => s.proxies.dangleProxyNames; -export const getShowModalClosePrevConns = (s: State) => - s.proxies.showModalClosePrevConns; +export const getShowModalClosePrevConns = (s: State) => s.proxies.showModalClosePrevConns; + +function mapLatency(names: string[], getProxy: (name: string) => { history: LatencyHistory }) { + const result: DelayMapping = {}; + for (const name of names) { + const p = getProxy(name) || { history: [] }; + const history = p.history; + const h = history[history.length - 1]; + if (h && typeof h.delay === 'number') { + result[name] = { number: h.delay }; + } + } + return result; +} export function fetchProxies(apiConfig: ClashAPIConfig) { return async (dispatch: any, getState: any) => { @@ -59,37 +72,28 @@ export function fetchProxies(apiConfig: ClashAPIConfig) { proxiesAPI.fetchProviderProxies(apiConfig), ]); - const { - providers: proxyProviders, - proxies: providerProxies, - } = formatProxyProviders(providersData.providers); - const proxies = { ...providerProxies, ...proxiesData.proxies }; - const [groupNames, proxyNames] = retrieveGroupNamesFrom(proxies); + const { proxyProviders, providerProxyRecord } = formatProxyProviders(providersData.providers); - const delayPrev = getDelay(getState()); - const delayNext = { ...delayPrev }; + const proxies = { ...providerProxyRecord, ...proxiesData.proxies }; + const [groupNames, proxyNames] = retrieveGroupNamesFrom(proxies); - for (let i = 0; i < proxyNames.length; i++) { - const name = proxyNames[i]; - const { history } = proxies[name] || { history: [] }; - const h = history[history.length - 1]; - if (h && typeof h.delay === 'number') { - delayNext[name] = { number: h.delay }; - } - } + const delayNext = { + ...getDelay(getState()), + ...mapLatency(Object.keys(proxies), (name) => proxies[name]), + }; // proxies that are not from a provider const dangleProxyNames = []; for (const v of proxyNames) { - if (!providerProxies[v]) dangleProxyNames.push(v); + if (!providerProxyRecord[v]) dangleProxyNames.push(v); } dispatch('store/proxies#fetchProxies', (s: State) => { s.proxies.proxies = proxies; s.proxies.groupNames = groupNames; + s.proxies.dangleProxyNames = dangleProxyNames; s.proxies.delay = delayNext; s.proxies.proxyProviders = proxyProviders; - s.proxies.dangleProxyNames = dangleProxyNames; }); }; } @@ -122,10 +126,7 @@ export function updateProviders(apiConfig: ClashAPIConfig, names: string[]) { }; } -async function healthcheckProviderByNameInternal( - apiConfig: ClashAPIConfig, - name: string -) { +async function healthcheckProviderByNameInternal(apiConfig: ClashAPIConfig, name: string) { try { await proxiesAPI.healthcheckProviderByName(apiConfig, name); } catch (x) { @@ -133,10 +134,7 @@ async function healthcheckProviderByNameInternal( } } -export function healthcheckProviderByName( - apiConfig: ClashAPIConfig, - name: string -) { +export function healthcheckProviderByName(apiConfig: ClashAPIConfig, name: string) { return async (dispatch: DispatchFn) => { await healthcheckProviderByNameInternal(apiConfig, name); // should be optimized @@ -169,16 +167,10 @@ async function closeGroupConns( } } - await Promise.all( - idsToClose.map((id) => connAPI.closeConnById(apiConfig, id).catch(noop)) - ); + await Promise.all(idsToClose.map((id) => connAPI.closeConnById(apiConfig, id).catch(noop))); } -function resolveChain( - proxies: ProxiesMapping, - groupName: string, - itemName: string -) { +function resolveChain(proxies: ProxiesMapping, groupName: string, itemName: string) { const chain = [itemName, groupName]; let child: ProxyItem; @@ -198,11 +190,7 @@ async function switchProxyImpl( itemName: string ) { try { - const res = await proxiesAPI.requestToSwitchProxy( - apiConfig, - groupName, - itemName - ); + const res = await proxiesAPI.requestToSwitchProxy(apiConfig, groupName, itemName); if (res.ok === false) { throw new Error(`failed to switch proxy: res.statusText`); } @@ -220,11 +208,6 @@ async function switchProxyImpl( // no wait closePrevConns(apiConfig, proxies, { groupName, itemName }); } - - /* dispatch('showModalClosePrevConns', (s: GlobalState) => { */ - /* s.proxies.showModalClosePrevConns = true; */ - /* s.proxies.switchProxyCtx = { to: { groupName, itemName } }; */ - /* }); */ } function closeModalClosePrevConns() { @@ -268,16 +251,10 @@ function closePrevConnsAndTheModal(apiConfig: ClashAPIConfig) { }; } -export function switchProxy( - apiConfig: ClashAPIConfig, - groupName: string, - itemName: string -) { +export function switchProxy(apiConfig: ClashAPIConfig, groupName: string, itemName: string) { return async (dispatch: DispatchFn, getState: GetStateFn) => { // switch proxy asynchronously - switchProxyImpl(dispatch, getState, apiConfig, groupName, itemName).catch( - noop - ); + switchProxyImpl(dispatch, getState, apiConfig, groupName, itemName).catch(noop); // optimistic UI update dispatch('store/proxies#switchProxy', (s) => { @@ -292,25 +269,13 @@ export function switchProxy( function requestDelayForProxyOnce(apiConfig: ClashAPIConfig, name: string) { return async (dispatch: DispatchFn, getState: GetStateFn) => { const latencyTestUrl = getLatencyTestUrl(getState()); - const res = await proxiesAPI.requestDelayForProxy( - apiConfig, - name, - latencyTestUrl - ); + const res = await proxiesAPI.requestDelayForProxy(apiConfig, name, latencyTestUrl); let error = ''; if (res.ok === false) { error = res.statusText; } const { delay } = await res.json(); - - const delayPrev = getDelay(getState()); - const delayNext = { - ...delayPrev, - [name]: { - error, - number: delay, - }, - }; + const delayNext = { ...getDelay(getState()), [name]: { error, number: delay } }; dispatch('requestDelayForProxyOnce', (s) => { s.proxies.delay = delayNext; @@ -324,17 +289,35 @@ export function requestDelayForProxy(apiConfig: ClashAPIConfig, name: string) { }; } -export function requestDelayForProxies( - apiConfig: ClashAPIConfig, - names: string[] -) { +export function requestDelayForProxies(apiConfig: ClashAPIConfig, names: string[]) { return async (dispatch: DispatchFn, getState: GetStateFn) => { - const proxyNames = getDangleProxyNames(getState()); + const proxies = getProxies(getState()); + const latencyTestUrl = getLatencyTestUrl(getState()); + + const proxyDedupMap = new Map<string, boolean>(); + const providerDedupMap = new Map<string, boolean>(); - const works = names - // remove names that are provided by proxy providers - .filter((p) => proxyNames.indexOf(p) > -1) - .map((p) => dispatch(requestDelayForProxy(apiConfig, p))); + const works = names.map((name) => { + const p = proxies[name]; + if (!p.__provider) { + if (proxyDedupMap.get(name)) { + return undefined; + } else { + proxyDedupMap.set(name, true); + return proxiesAPI.requestDelayForProxy(apiConfig, name, latencyTestUrl); + } + } else if (p.__provider) { + // this one is from a proxy provider + if (providerDedupMap.get(p.__provider)) { + return undefined; + } else { + providerDedupMap.set(p.__provider, true); + return healthcheckProviderByNameInternal(apiConfig, p.__provider); + } + } else { + return undefined; + } + }); await Promise.all(works); await dispatch(fetchProxies(apiConfig)); }; @@ -343,8 +326,9 @@ export function requestDelayForProxies( export function requestDelayAll(apiConfig: ClashAPIConfig) { return async (dispatch: DispatchFn, getState: GetStateFn) => { const proxyNames = getDangleProxyNames(getState()); + const latencyTestUrl = getLatencyTestUrl(getState()); await Promise.all( - proxyNames.map((p) => dispatch(requestDelayForProxy(apiConfig, p))) + proxyNames.map((p) => proxiesAPI.requestDelayForProxy(apiConfig, p, latencyTestUrl)) ); const proxyProviders = getProxyProviders(getState()); // one by one @@ -364,7 +348,7 @@ function retrieveGroupNamesFrom(proxies: Record<string, ProxyItem>) { if (p.all && Array.isArray(p.all)) { groupNames.push(prop); if (prop === 'GLOBAL') { - globalAll = p.all; + globalAll = Array.from(p.all); } } else if (NonProxyTypes.indexOf(p.type) < 0) { proxyNames.push(prop); @@ -386,15 +370,14 @@ type ProvidersRaw = { [key: string]: ProxyProvider; }; -function formatProxyProviders( - providersInput: ProvidersRaw -): { - providers: Array<FormattedProxyProvider>; - proxies: { [key: string]: ProxyItem }; +function formatProxyProviders(providersInput: ProvidersRaw): { + proxyProviders: Array<FormattedProxyProvider>; + providerProxyRecord: ProxiesMapping; } { const keys = Object.keys(providersInput); - const providers = []; - const proxies = {}; + const proxyProviders = []; + const providerProxyRecord: ProxiesMapping = {}; + for (let i = 0; i < keys.length; i++) { const provider: ProxyProvider = providersInput[keys[i]]; if (provider.name === 'default' || provider.vehicleType === 'Compatible') { @@ -404,19 +387,16 @@ function formatProxyProviders( const names = []; for (let j = 0; j < proxiesArr.length; j++) { const proxy = proxiesArr[j]; - proxies[proxy.name] = proxy; + providerProxyRecord[proxy.name] = { ...proxy, __provider: provider.name }; names.push(proxy.name); } // mutate directly provider.proxies = names; - providers.push(provider); + proxyProviders.push(provider); } - return { - providers, - proxies, - }; + return { proxyProviders, providerProxyRecord }; } export const actions = { diff --git a/src/store/types.ts b/src/store/types.ts index 3a3e412..faf8a92 100644 --- a/src/store/types.ts +++ b/src/store/types.ts @@ -44,39 +44,45 @@ export type TunPartial<T> = { ///// store.proxies -type LatencyHistory = Array<{ time: string; delay: number }>; -type PrimitiveProxyType = 'Shadowsocks' | 'Snell' | 'Socks5' | 'Http' | 'Vmess'; +type LatencyHistoryItem = { time: string; delay: number }; +export type LatencyHistory = LatencyHistoryItem[]; + export type ProxyItem = { name: string; - type: PrimitiveProxyType; + type: string; history: LatencyHistory; all?: string[]; now?: string; + + __provider?: string; }; + +export type ProxyDelayItem = { + number?: number; +}; + export type ProxiesMapping = Record<string, ProxyItem>; -export type DelayMapping = Record<string, { number?: number }>; +export type DelayMapping = Record<string, ProxyDelayItem>; export type ProxyProvider = { name: string; type: 'Proxy'; updatedAt: string; vehicleType: 'HTTP' | 'File' | 'Compatible'; - proxies: Array<ProxyItem>; + proxies: ProxyItem[]; }; -export type FormattedProxyProvider = Omit<ProxyProvider, 'proxies'> & { - proxies: string[]; -}; +export type FormattedProxyProvider = Omit<ProxyProvider, 'proxies'> & { proxies: string[] }; export type SwitchProxyCtxItem = { groupName: string; itemName: string }; -type SwitchProxyCtx = { - to: SwitchProxyCtxItem; -}; +type SwitchProxyCtx = { to: SwitchProxyCtxItem }; + export type StateProxies = { - proxies: ProxiesMapping; - delay: DelayMapping; groupNames: string[]; proxyProviders?: FormattedProxyProvider[]; + + proxies: ProxiesMapping; + delay: DelayMapping; dangleProxyNames?: string[]; showModalClosePrevConns: boolean; |
