mirror of
https://github.com/MetaCubeX/metacubexd.git
synced 2024-11-27 10:44:02 +08:00
refactor: add api module
This commit is contained in:
parent
34ea1f1c56
commit
71fd8ab22e
167
src/apis/index.ts
Normal file
167
src/apis/index.ts
Normal file
@ -0,0 +1,167 @@
|
||||
import { createSignal } from 'solid-js'
|
||||
import { toast } from 'solid-toast'
|
||||
import { setBackendConfig, useRequest } from '~/signals'
|
||||
import {
|
||||
BackendVersion,
|
||||
Config,
|
||||
Proxy,
|
||||
ProxyProvider,
|
||||
Rule,
|
||||
RuleProvider,
|
||||
} from '~/types'
|
||||
|
||||
export const closeAllConnectionsAPI = () => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.delete('connections')
|
||||
}
|
||||
|
||||
export const closeSingleConnectionAPI = (id: string) => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.delete(`connections/${id}`)
|
||||
}
|
||||
|
||||
export const [updatingGEODatabases, setUpdatingGEODatabases] =
|
||||
createSignal(false)
|
||||
export const [upgradingBackend, setUpgradingBackend] = createSignal(false)
|
||||
export const [restartingBackend, setRestartingBackend] = createSignal(false)
|
||||
|
||||
export const updateGEODatabasesAPI = async () => {
|
||||
const request = useRequest()
|
||||
setUpdatingGEODatabases(true)
|
||||
try {
|
||||
await request.post('configs/geo')
|
||||
} catch {}
|
||||
setUpdatingGEODatabases(false)
|
||||
}
|
||||
|
||||
export const upgradeBackendAPI = async () => {
|
||||
const request = useRequest()
|
||||
setUpgradingBackend(true)
|
||||
try {
|
||||
await request.post('upgrade')
|
||||
} catch {}
|
||||
setUpgradingBackend(false)
|
||||
}
|
||||
|
||||
export const restartBackendAPI = async () => {
|
||||
const request = useRequest()
|
||||
setRestartingBackend(true)
|
||||
try {
|
||||
await request.post('restart')
|
||||
} catch {}
|
||||
setRestartingBackend(false)
|
||||
}
|
||||
|
||||
export const fetchBackendConfigAPI = () => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.get('configs').json<Config>()
|
||||
}
|
||||
|
||||
export const updateBackendConfigAPI = async (
|
||||
key: keyof Config,
|
||||
value: Config[keyof Config],
|
||||
) => {
|
||||
try {
|
||||
const request = useRequest()
|
||||
|
||||
await request
|
||||
.patch('configs', {
|
||||
body: JSON.stringify({
|
||||
[key]: value,
|
||||
}),
|
||||
})
|
||||
.json<Config>()
|
||||
|
||||
const updatedConfig = await fetchBackendConfigAPI()
|
||||
|
||||
setBackendConfig(updatedConfig)
|
||||
} catch (err) {
|
||||
toast.error((err as Error).message)
|
||||
}
|
||||
}
|
||||
|
||||
export const fetchBackendVersionAPI = async () => {
|
||||
const request = useRequest()
|
||||
|
||||
const { version } = await request.get('version').json<BackendVersion>()
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
export const fetchProxyProvidersAPI = () => {
|
||||
const request = useRequest()
|
||||
|
||||
return request
|
||||
.get('providers/proxies')
|
||||
.json<{ providers: Record<string, ProxyProvider> }>()
|
||||
}
|
||||
|
||||
export const fetchProxiesAPI = () => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.get('proxies').json<{ proxies: Record<string, Proxy> }>()
|
||||
}
|
||||
|
||||
export const updateProxyProviderAPI = (providerName: string) => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.put(`providers/proxies/${providerName}`)
|
||||
}
|
||||
|
||||
export const proxyProviderHealthCheck = (providerName: string) => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.get(`providers/proxies/${providerName}/healthcheck`, {
|
||||
timeout: 20 * 1000,
|
||||
})
|
||||
}
|
||||
|
||||
export const selectProxyInGroupAPI = (groupName: string, proxyName: string) => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.put(`proxies/${groupName}`, {
|
||||
body: JSON.stringify({
|
||||
name: proxyName,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
export const proxyGroupLatencyTestAPI = (
|
||||
groupName: string,
|
||||
url: string,
|
||||
timeout: number,
|
||||
) => {
|
||||
const request = useRequest()
|
||||
|
||||
return request
|
||||
.get(`group/${groupName}/delay`, {
|
||||
searchParams: {
|
||||
url,
|
||||
timeout,
|
||||
},
|
||||
})
|
||||
.json<Record<string, number>>()
|
||||
}
|
||||
|
||||
export const fetchRulesAPI = () => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.get('rules').json<{ rules: Record<string, Rule> }>()
|
||||
}
|
||||
|
||||
export const fetchRuleProvidersAPI = () => {
|
||||
const request = useRequest()
|
||||
|
||||
return request
|
||||
.get('providers/rules')
|
||||
.json<{ providers: Record<string, RuleProvider> }>()
|
||||
}
|
||||
|
||||
export const updateRuleProviderAPI = (providerName: string) => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.put(`providers/rules/${providerName}`)
|
||||
}
|
@ -11,6 +11,17 @@ import {
|
||||
onMount,
|
||||
} from 'solid-js'
|
||||
import { z } from 'zod'
|
||||
import {
|
||||
fetchBackendConfigAPI,
|
||||
fetchBackendVersionAPI,
|
||||
restartBackendAPI,
|
||||
restartingBackend,
|
||||
updateBackendConfigAPI,
|
||||
updateGEODatabasesAPI,
|
||||
updatingGEODatabases,
|
||||
upgradeBackendAPI,
|
||||
upgradingBackend,
|
||||
} from '~/apis'
|
||||
import { Button } from '~/components'
|
||||
import {
|
||||
LANG,
|
||||
@ -28,7 +39,6 @@ import {
|
||||
backendConfig,
|
||||
favDayTheme,
|
||||
favNightTheme,
|
||||
fetchBackendConfig,
|
||||
latencyTestTimeoutDuration,
|
||||
proxiesOrderingType,
|
||||
proxiesPreviewType,
|
||||
@ -47,12 +57,11 @@ import {
|
||||
setTwemoji,
|
||||
setUrlForLatencyTest,
|
||||
tableSize,
|
||||
updateBackendConfig,
|
||||
urlForLatencyTest,
|
||||
useRequest,
|
||||
useTwemoji,
|
||||
} from '~/signals'
|
||||
import type { BackendVersion, DNSQuery } from '~/types'
|
||||
import type { DNSQuery } from '~/types'
|
||||
|
||||
const dnsQueryFormSchema = z.object({
|
||||
name: z.string(),
|
||||
@ -130,7 +139,6 @@ const configFormSchema = z.object({
|
||||
|
||||
const ConfigForm = () => {
|
||||
const [t] = useI18n()
|
||||
const request = useRequest()
|
||||
|
||||
const portsList = [
|
||||
{
|
||||
@ -160,46 +168,18 @@ const ConfigForm = () => {
|
||||
>({ extend: validator({ schema: configFormSchema }) })
|
||||
|
||||
onMount(async () => {
|
||||
const configs = await fetchBackendConfig()
|
||||
const configs = await fetchBackendConfigAPI()
|
||||
setBackendConfig(configs)
|
||||
setInitialValues(configs)
|
||||
reset()
|
||||
})
|
||||
|
||||
const [updatingGEODatabases, setUpdatingGEODatabases] = createSignal(false)
|
||||
const [upgrading, setUpgrading] = createSignal(false)
|
||||
const [restarting, setRestarting] = createSignal(false)
|
||||
|
||||
const onUpdateGEODatabases = async () => {
|
||||
setUpdatingGEODatabases(true)
|
||||
try {
|
||||
await request.post('configs/geo')
|
||||
} catch {}
|
||||
setUpdatingGEODatabases(false)
|
||||
}
|
||||
|
||||
const onUpgrade = async () => {
|
||||
setUpgrading(true)
|
||||
try {
|
||||
await request.post('upgrade')
|
||||
} catch {}
|
||||
setUpgrading(false)
|
||||
}
|
||||
|
||||
const onRestart = async () => {
|
||||
setRestarting(true)
|
||||
try {
|
||||
await request.post('restart')
|
||||
} catch {}
|
||||
setRestarting(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div class="flex flex-col gap-4">
|
||||
<select
|
||||
class="select select-bordered"
|
||||
value={backendConfig()?.mode}
|
||||
onChange={(e) => updateBackendConfig('mode', e.target.value)}
|
||||
onChange={(e) => updateBackendConfigAPI('mode', e.target.value)}
|
||||
>
|
||||
<option value={MODE_OPTIONS.Global}>{t('global')}</option>
|
||||
<option value={MODE_OPTIONS.Rule}>{t('rule')}</option>
|
||||
@ -226,15 +206,18 @@ const ConfigForm = () => {
|
||||
</form>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<Button loading={updatingGEODatabases()} onClick={onUpdateGEODatabases}>
|
||||
<Button
|
||||
loading={updatingGEODatabases()}
|
||||
onClick={updateGEODatabasesAPI}
|
||||
>
|
||||
{t('updateGEODatabases')}
|
||||
</Button>
|
||||
|
||||
<Button loading={upgrading()} onClick={onUpgrade}>
|
||||
<Button loading={upgradingBackend()} onClick={upgradeBackendAPI}>
|
||||
{t('upgradeCore')}
|
||||
</Button>
|
||||
|
||||
<Button loading={restarting()} onClick={onRestart}>
|
||||
<Button loading={restartingBackend()} onClick={restartBackendAPI}>
|
||||
{t('restartCore')}
|
||||
</Button>
|
||||
</div>
|
||||
@ -332,12 +315,12 @@ const ConfigForXd = () => {
|
||||
|
||||
const checkboxList = [
|
||||
{
|
||||
label: 'renderInTwoColumns',
|
||||
label: t('renderInTwoColumns'),
|
||||
value: renderInTwoColumns,
|
||||
onChange: setRenderInTwoColumns,
|
||||
},
|
||||
{
|
||||
label: 'autoSwitchTheme',
|
||||
label: t('autoSwitchTheme'),
|
||||
value: autoSwitchTheme,
|
||||
onChange: (value: boolean) => {
|
||||
setAutoSwitchTheme(value)
|
||||
@ -346,7 +329,7 @@ const ConfigForXd = () => {
|
||||
subChild: autoSwitchThemeSubChild,
|
||||
},
|
||||
{
|
||||
label: 'useTwemoji',
|
||||
label: t('useTwemoji'),
|
||||
value: useTwemoji,
|
||||
onChange: setTwemoji,
|
||||
},
|
||||
@ -358,7 +341,7 @@ const ConfigForXd = () => {
|
||||
{(checkbox) => (
|
||||
<>
|
||||
<div class="flex flex-col">
|
||||
<ConfigTitle>{t(checkbox.label)}</ConfigTitle>
|
||||
<ConfigTitle>{checkbox.label}</ConfigTitle>
|
||||
|
||||
<input
|
||||
type="checkbox"
|
||||
@ -444,12 +427,10 @@ const ConfigForXd = () => {
|
||||
}
|
||||
|
||||
const Versions = () => {
|
||||
const request = useRequest()
|
||||
|
||||
const [backendVersion, setBackendVersion] = createSignal('')
|
||||
|
||||
onMount(async () => {
|
||||
const { version } = await request.get('version').json<BackendVersion>()
|
||||
const version = await fetchBackendVersionAPI()
|
||||
|
||||
setBackendVersion(version)
|
||||
})
|
||||
|
@ -30,6 +30,7 @@ import byteSize from 'byte-size'
|
||||
import dayjs from 'dayjs'
|
||||
import { For, Index, createMemo, createSignal } from 'solid-js'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { closeAllConnectionsAPI, closeSingleConnectionAPI } from '~/apis'
|
||||
import {
|
||||
Button,
|
||||
ConnectionsTableDetailsModal,
|
||||
@ -41,12 +42,7 @@ import {
|
||||
CONNECTIONS_TABLE_INITIAL_COLUMN_VISIBILITY,
|
||||
} from '~/constants'
|
||||
import { formatTimeFromNow } from '~/helpers'
|
||||
import {
|
||||
tableSize,
|
||||
tableSizeClassName,
|
||||
useConnections,
|
||||
useRequest,
|
||||
} from '~/signals'
|
||||
import { tableSize, tableSizeClassName, useConnections } from '~/signals'
|
||||
import type { Connection } from '~/types'
|
||||
|
||||
type ColumnVisibility = Partial<Record<CONNECTIONS_TABLE_ACCESSOR_KEY, boolean>>
|
||||
@ -72,14 +68,10 @@ const fuzzyFilter: FilterFn<Connection> = (row, columnId, value, addMeta) => {
|
||||
|
||||
export default () => {
|
||||
const [t] = useI18n()
|
||||
const request = useRequest()
|
||||
|
||||
const [activeTab, setActiveTab] = createSignal(ActiveTab.activeConnections)
|
||||
const { activeConnections, closedConnections, paused, setPaused } =
|
||||
useConnections()
|
||||
const onAllConnectionsClose = () => request.delete('connections')
|
||||
const onSingleConnectionClose = (id: string) =>
|
||||
request.delete(`connections/${id}`)
|
||||
|
||||
const [globalFilter, setGlobalFilter] = createSignal('')
|
||||
const [columnVisibility, setColumnVisibility] = makePersisted(
|
||||
@ -137,7 +129,7 @@ export default () => {
|
||||
<div class="flex h-4 items-center">
|
||||
<Button
|
||||
class="btn-circle btn-xs"
|
||||
onClick={() => onSingleConnectionClose(row.original.id)}
|
||||
onClick={() => closeSingleConnectionAPI(row.original.id)}
|
||||
>
|
||||
<IconCircleX size="16" />
|
||||
</Button>
|
||||
@ -352,9 +344,9 @@ export default () => {
|
||||
if (table.getState().globalFilter) {
|
||||
table
|
||||
.getFilteredRowModel()
|
||||
.rows.forEach(({ id }) => onSingleConnectionClose(id))
|
||||
.rows.forEach(({ id }) => closeSingleConnectionAPI(id))
|
||||
} else {
|
||||
onAllConnectionsClose()
|
||||
closeAllConnectionsAPI()
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { makePersisted } from '@solid-primitives/storage'
|
||||
import { createSignal } from 'solid-js'
|
||||
import { toast } from 'solid-toast'
|
||||
import {
|
||||
LATENCY_QUALITY_MAP_HTTP,
|
||||
LATENCY_QUALITY_MAP_HTTPS,
|
||||
@ -8,7 +7,7 @@ import {
|
||||
PROXIES_PREVIEW_TYPE,
|
||||
TAILWINDCSS_SIZE,
|
||||
} from '~/constants'
|
||||
import { setCurTheme, useRequest } from '~/signals'
|
||||
import { setCurTheme } from '~/signals'
|
||||
import { Config } from '~/types'
|
||||
|
||||
export const [proxiesPreviewType, setProxiesPreviewType] = makePersisted(
|
||||
@ -107,32 +106,3 @@ export const useAutoSwitchTheme = () => {
|
||||
}
|
||||
|
||||
export const [backendConfig, setBackendConfig] = createSignal<Config>()
|
||||
|
||||
export const fetchBackendConfig = () => {
|
||||
const request = useRequest()
|
||||
|
||||
return request.get('configs').json<Config>()
|
||||
}
|
||||
|
||||
export const updateBackendConfig = async (
|
||||
key: keyof Config,
|
||||
value: Config[keyof Config],
|
||||
) => {
|
||||
try {
|
||||
const request = useRequest()
|
||||
|
||||
await request
|
||||
.patch('configs', {
|
||||
body: JSON.stringify({
|
||||
[key]: value,
|
||||
}),
|
||||
})
|
||||
.json<Config>()
|
||||
|
||||
const updatedConfig = await fetchBackendConfig()
|
||||
|
||||
setBackendConfig(updatedConfig)
|
||||
} catch (err) {
|
||||
toast.error((err as Error).message)
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,22 @@
|
||||
import { createSignal, untrack } from 'solid-js'
|
||||
import {
|
||||
closeSingleConnectionAPI,
|
||||
fetchProxiesAPI,
|
||||
fetchProxyProvidersAPI,
|
||||
proxyGroupLatencyTestAPI,
|
||||
proxyProviderHealthCheck,
|
||||
selectProxyInGroupAPI,
|
||||
updateProxyProviderAPI,
|
||||
} from '~/apis'
|
||||
import {
|
||||
autoCloseConns,
|
||||
latencyTestTimeoutDuration,
|
||||
urlForLatencyTest,
|
||||
useRequest,
|
||||
} from '~/signals'
|
||||
import type { Proxy, ProxyNode, ProxyProvider } from '~/types'
|
||||
import {
|
||||
latestConnectionMsg,
|
||||
mergeAllConnections,
|
||||
restructRawMsgToConnection,
|
||||
} from './connections'
|
||||
urlForLatencyTest,
|
||||
} from '~/signals'
|
||||
import type { Proxy, ProxyNode, ProxyProvider } from '~/types'
|
||||
|
||||
type ProxyInfo = {
|
||||
name: string
|
||||
@ -50,14 +56,10 @@ const setProxiesInfo = (proxies: (Proxy | ProxyNode)[]) => {
|
||||
}
|
||||
|
||||
export const useProxies = () => {
|
||||
const request = useRequest()
|
||||
|
||||
const updateProxies = async () => {
|
||||
const [{ providers }, { proxies }] = await Promise.all([
|
||||
request
|
||||
.get('providers/proxies')
|
||||
.json<{ providers: Record<string, ProxyProvider> }>(),
|
||||
request.get('proxies').json<{ proxies: Record<string, Proxy> }>(),
|
||||
fetchProxyProvidersAPI(),
|
||||
fetchProxiesAPI(),
|
||||
])
|
||||
|
||||
const sortIndex = [...(proxies['GLOBAL'].all ?? []), 'GLOBAL']
|
||||
@ -85,15 +87,11 @@ export const useProxies = () => {
|
||||
const proxyGroupList = proxies().slice()
|
||||
const proxyGroup = proxyGroupList.find((i) => i.name === proxy.name)!
|
||||
|
||||
await request.put(`proxies/${proxy.name}`, {
|
||||
body: JSON.stringify({
|
||||
name: proxyName,
|
||||
}),
|
||||
})
|
||||
await selectProxyInGroupAPI(proxy.name, proxyName)
|
||||
|
||||
if (autoCloseConns()) {
|
||||
// we dont use activeConns from useConnection here for better performance
|
||||
// and we use empty array to restruct msg because they are closed and they won't have speed anyway
|
||||
// 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
|
||||
untrack(() => {
|
||||
const activeConns = restructRawMsgToConnection(
|
||||
latestConnectionMsg()?.connections ?? [],
|
||||
@ -103,7 +101,7 @@ export const useProxies = () => {
|
||||
if (activeConns.length > 0) {
|
||||
activeConns.forEach(({ id, chains }) => {
|
||||
if (chains.includes(proxy.name)) {
|
||||
request.delete(`connections/${id}`)
|
||||
closeSingleConnectionAPI(id)
|
||||
}
|
||||
})
|
||||
mergeAllConnections(activeConns)
|
||||
@ -116,14 +114,11 @@ export const useProxies = () => {
|
||||
}
|
||||
|
||||
const latencyTestByProxyGroupName = async (proxyGroupName: string) => {
|
||||
const data: Record<string, number> = await request
|
||||
.get(`group/${proxyGroupName}/delay`, {
|
||||
searchParams: {
|
||||
url: urlForLatencyTest(),
|
||||
timeout: latencyTestTimeoutDuration(),
|
||||
},
|
||||
})
|
||||
.json()
|
||||
const data = await proxyGroupLatencyTestAPI(
|
||||
proxyGroupName,
|
||||
urlForLatencyTest(),
|
||||
latencyTestTimeoutDuration(),
|
||||
)
|
||||
|
||||
setLatencyMap({
|
||||
...latencyMap(),
|
||||
@ -131,26 +126,22 @@ export const useProxies = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const updateProviderByProviderName = async (proxyProviderName: string) => {
|
||||
const updateProviderByProviderName = async (providerName: string) => {
|
||||
try {
|
||||
await request.put(`providers/proxies/${proxyProviderName}`)
|
||||
await updateProxyProviderAPI(providerName)
|
||||
} catch {}
|
||||
await updateProxies()
|
||||
}
|
||||
|
||||
const updateAllProvider = async () => {
|
||||
await Promise.allSettled(
|
||||
proxyProviders().map((provider) =>
|
||||
request.put(`providers/proxies/${provider.name}`),
|
||||
),
|
||||
proxyProviders().map((provider) => updateProxyProviderAPI(provider.name)),
|
||||
)
|
||||
await updateProxies()
|
||||
}
|
||||
|
||||
const healthCheckByProviderName = async (providerName: string) => {
|
||||
await request.get(`providers/proxies/${providerName}/healthcheck`, {
|
||||
timeout: 20 * 1000,
|
||||
})
|
||||
await proxyProviderHealthCheck(providerName)
|
||||
await updateProxies()
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { createSignal } from 'solid-js'
|
||||
import { useRequest } from '~/signals'
|
||||
import {
|
||||
fetchRuleProvidersAPI,
|
||||
fetchRulesAPI,
|
||||
updateRuleProviderAPI,
|
||||
} from '~/apis'
|
||||
import type { Rule, RuleProvider } from '~/types'
|
||||
|
||||
export const useRules = () => {
|
||||
const request = useRequest()
|
||||
const [rules, setRules] = createSignal<Rule[]>([])
|
||||
const [ruleProviders, setRuleProviders] = createSignal<RuleProvider[]>([])
|
||||
|
||||
const updateRules = async () => {
|
||||
const [{ rules }, { providers }] = await Promise.all([
|
||||
request.get('rules').json<{ rules: Record<string, Rule> }>(),
|
||||
request
|
||||
.get('providers/rules')
|
||||
.json<{ providers: Record<string, RuleProvider> }>(),
|
||||
fetchRulesAPI(),
|
||||
fetchRuleProvidersAPI(),
|
||||
])
|
||||
|
||||
setRules(Object.values(rules))
|
||||
@ -21,15 +22,13 @@ export const useRules = () => {
|
||||
|
||||
const updateAllRuleProvider = async () => {
|
||||
await Promise.all(
|
||||
ruleProviders().map((provider) => {
|
||||
return request.put(`providers/rules/${provider.name}`)
|
||||
}),
|
||||
ruleProviders().map((provider) => updateRuleProviderAPI(provider.name)),
|
||||
)
|
||||
await updateRules()
|
||||
}
|
||||
|
||||
const updateRuleProviderByName = async (name: string) => {
|
||||
await request.put(`providers/rules/${name}`)
|
||||
const updateRuleProviderByName = async (providerName: string) => {
|
||||
await updateRuleProviderAPI(providerName)
|
||||
await updateRules()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user