mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-30 10:42:09 +08:00
refactor(backend): specta ipc bindings (#8195)
* refactor(ipc): generate bindings with Specta * fix(profile): project IPC inputs to consumed fields * fix(events): remove unused refresh payloads * fix(webdav): return only consumed backup metadata * fix(network): trim unused interface metadata * fix(sysinfo): return only displayed system fields * chore(knip): check generated runtime exports * fix(proxy): confirm runtime chain updates before UI changes * fix(clipboard): propagate proxy environment copy failures * refactor(dns): remove ignored runtime patch * refactor(core): trim unused upgrade response fields * refactor(ipc): avoid redundant response copies * refactor(proxy): clarify automatic proxy query naming * chore(tests): remove added IPC regression tests * refactor(ipc): enforce typed command boundaries * chore(contract): check generated bindings before push * refactor(ipc): remove unused proxy liveness payloads
This commit is contained in:
@@ -445,10 +445,14 @@ export const ProxyChain = ({
|
||||
if (isConnected) {
|
||||
setIsConnecting(true)
|
||||
try {
|
||||
await mutate(() => updateProxyChainConfigInRuntime(null), {
|
||||
id: 'update-proxy-chain-runtime',
|
||||
errorNotice: false,
|
||||
})
|
||||
const result = await mutate(
|
||||
() => updateProxyChainConfigInRuntime(null),
|
||||
{
|
||||
id: 'update-proxy-chain-runtime',
|
||||
errorNotice: false,
|
||||
},
|
||||
)
|
||||
if (!result.ok) return
|
||||
|
||||
const targetGroup =
|
||||
mode === 'global'
|
||||
@@ -461,7 +465,7 @@ export const ProxyChain = ({
|
||||
id: `select-proxy-node:${targetGroup}`,
|
||||
errorNotice: false,
|
||||
})
|
||||
recordSelection(targetGroup, 'DIRECT')
|
||||
await recordSelection(targetGroup, 'DIRECT')
|
||||
} catch {
|
||||
if (currentProxyChain.length >= 1) {
|
||||
try {
|
||||
@@ -473,7 +477,7 @@ export const ProxyChain = ({
|
||||
errorNotice: false,
|
||||
},
|
||||
)
|
||||
recordSelection(targetGroup, currentProxyChain[0].name)
|
||||
await recordSelection(targetGroup, currentProxyChain[0].name)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
@@ -519,10 +523,14 @@ export const ProxyChain = ({
|
||||
// 第一步:保存链式代理配置
|
||||
const chainProxies = currentProxyChain.map((node) => node.name)
|
||||
debugLog('Saving chain config:', chainProxies)
|
||||
await mutate(() => updateProxyChainConfigInRuntime(chainProxies), {
|
||||
id: 'update-proxy-chain-runtime',
|
||||
errorNotice: false,
|
||||
})
|
||||
const result = await mutate(
|
||||
() => updateProxyChainConfigInRuntime(chainProxies),
|
||||
{
|
||||
id: 'update-proxy-chain-runtime',
|
||||
errorNotice: false,
|
||||
},
|
||||
)
|
||||
if (!result.ok) return
|
||||
debugLog('Chain configuration saved successfully')
|
||||
|
||||
// 第二步:连接到代理链的最后一个节点
|
||||
@@ -545,12 +553,12 @@ export const ProxyChain = ({
|
||||
)
|
||||
// The chain moves the group like any other selection, so the profile has to learn about
|
||||
// it: what the profile holds is what gets re-applied the next time the core starts.
|
||||
recordSelection(targetGroup || 'GLOBAL', lastNode.name)
|
||||
await recordSelection(targetGroup || 'GLOBAL', lastNode.name)
|
||||
localStorage.setItem('proxy-chain-group', targetGroup || 'GLOBAL')
|
||||
localStorage.setItem('proxy-chain-exit-node', lastNode.name)
|
||||
|
||||
// 刷新代理信息以更新连接状态
|
||||
refreshProxy()
|
||||
await refreshProxy()
|
||||
debugLog('Successfully connected to proxy chain')
|
||||
} catch (error) {
|
||||
console.error('Failed to connect to proxy chain:', error)
|
||||
@@ -619,14 +627,15 @@ export const ProxyChain = ({
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => {
|
||||
mutate(() => updateProxyChainConfigInRuntime(null), {
|
||||
void mutate(() => updateProxyChainConfigInRuntime(null), {
|
||||
id: 'update-proxy-chain-runtime',
|
||||
errorNotice: false,
|
||||
})
|
||||
localStorage.removeItem('proxy-chain-group')
|
||||
localStorage.removeItem('proxy-chain-exit-node')
|
||||
localStorage.removeItem('proxy-chain-items')
|
||||
onUpdateChain([])
|
||||
onFulfilled: () => {
|
||||
localStorage.removeItem('proxy-chain-group')
|
||||
localStorage.removeItem('proxy-chain-exit-node')
|
||||
localStorage.removeItem('proxy-chain-items')
|
||||
onUpdateChain([])
|
||||
},
|
||||
}).catch(() => {})
|
||||
}}
|
||||
sx={{
|
||||
color: theme.palette.error.main,
|
||||
|
||||
@@ -5,11 +5,11 @@ export type ProxyEmptyStateReason =
|
||||
| 'no-proxy-info'
|
||||
|
||||
type ProfileSummary = {
|
||||
current?: string
|
||||
current?: string | null
|
||||
items?: Array<{
|
||||
uid?: string
|
||||
type?: string
|
||||
}>
|
||||
uid?: string | null
|
||||
type?: string | null
|
||||
}> | null
|
||||
}
|
||||
|
||||
interface ProxyListStateInput {
|
||||
@@ -20,7 +20,7 @@ interface ProxyListStateInput {
|
||||
isRunningModePending: boolean
|
||||
}
|
||||
|
||||
const isSubscriptionProfile = (item: { type?: string }): boolean =>
|
||||
const isSubscriptionProfile = (item: { type?: string | null }): boolean =>
|
||||
item.type === 'remote' || item.type === 'local'
|
||||
|
||||
/** Decides only pre-render states; the built list owns whether it has renderable content. */
|
||||
|
||||
@@ -400,20 +400,26 @@ export function ProxyGroupsChain(props: ProxyGroupsChainProps) {
|
||||
setRuleMenuAnchor(null)
|
||||
}
|
||||
|
||||
const handleGroupSelect = (groupName: string) => {
|
||||
onGroupSelect(groupName)
|
||||
handleGroupMenuClose()
|
||||
|
||||
const handleGroupSelect = async (groupName: string) => {
|
||||
if (mode === 'rule') {
|
||||
mutate(() => updateProxyChainConfigInRuntime(null), {
|
||||
id: 'update-proxy-chain-runtime',
|
||||
errorNotice: false,
|
||||
})
|
||||
try {
|
||||
const result = await mutate(
|
||||
() => updateProxyChainConfigInRuntime(null),
|
||||
{
|
||||
id: 'update-proxy-chain-runtime',
|
||||
},
|
||||
)
|
||||
if (!result.ok) return
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
localStorage.removeItem('proxy-chain-group')
|
||||
localStorage.removeItem('proxy-chain-exit-node')
|
||||
localStorage.removeItem('proxy-chain-items')
|
||||
setProxyChain([])
|
||||
}
|
||||
onGroupSelect(groupName)
|
||||
handleGroupMenuClose()
|
||||
}
|
||||
|
||||
const handleCloseDuplicateWarning = useCallback(() => {
|
||||
|
||||
@@ -198,7 +198,7 @@ export const ProxyRender = memo(function ProxyRender(props: RenderProps) {
|
||||
{toolsOnLeft && proxyCount}
|
||||
<ProxyGroupTools
|
||||
side={toolsOnLeft ? 'left' : 'right'}
|
||||
url={group.testUrl}
|
||||
url={group.testUrl!}
|
||||
groupName={group.name}
|
||||
headState={headState!}
|
||||
onLocation={() => onLocation(group)}
|
||||
@@ -247,7 +247,7 @@ export const ProxyRender = memo(function ProxyRender(props: RenderProps) {
|
||||
return (
|
||||
<ProxyHead
|
||||
sx={{ pl: 2, pr: 3, mt: 0.5, mb: 1 }}
|
||||
url={group.testUrl}
|
||||
url={group.testUrl!}
|
||||
groupName={group.name}
|
||||
headState={headState!}
|
||||
onLocation={() => onLocation(group)}
|
||||
|
||||
@@ -17,7 +17,6 @@ const node = (memberIndex: number, delay: number, name = `${memberIndex}`) =>
|
||||
history: [{ delay }],
|
||||
extra: {
|
||||
'http://cp.cloudflare.com/generate_204': {
|
||||
alive: true,
|
||||
history: [{ time: new Date(0).toISOString(), delay }],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -110,13 +110,13 @@ const CHAIN_DELAY_GROUP = 'chain-mode'
|
||||
const virtualGroup = (members: ProxyGroupView['members']): ProxyGroupView => ({
|
||||
name: CHAIN_DELAY_GROUP,
|
||||
type: 'Selector',
|
||||
alive: true,
|
||||
udp: false,
|
||||
xudp: false,
|
||||
tfo: false,
|
||||
mptcp: false,
|
||||
smux: false,
|
||||
history: [],
|
||||
extra: {},
|
||||
members,
|
||||
})
|
||||
|
||||
@@ -237,7 +237,7 @@ export const useRenderList = (
|
||||
selected?.name ?? CHAIN_DELAY_GROUP,
|
||||
'',
|
||||
0,
|
||||
latencyTimeout,
|
||||
latencyTimeout!,
|
||||
)
|
||||
if (col > 1) {
|
||||
return groupOccurrences(occurrences, col).map((memberCol) => ({
|
||||
@@ -289,8 +289,8 @@ export const useRenderList = (
|
||||
key: group.name,
|
||||
group,
|
||||
headState,
|
||||
icon: group.icon,
|
||||
testUrl: group.testUrl,
|
||||
icon: group.icon!,
|
||||
testUrl: group.testUrl!,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -300,7 +300,7 @@ export const useRenderList = (
|
||||
group.name,
|
||||
headState.filterText,
|
||||
headState.sortType,
|
||||
latencyTimeout,
|
||||
latencyTimeout!,
|
||||
{
|
||||
matchCase: headState.filterMatchCase,
|
||||
matchWholeWord: headState.filterMatchWholeWord,
|
||||
@@ -337,11 +337,11 @@ export const useRenderList = (
|
||||
}
|
||||
|
||||
cache.set(group.name, {
|
||||
now: group.now,
|
||||
now: group.now!,
|
||||
members: group.members,
|
||||
headState,
|
||||
col,
|
||||
latencyTimeout,
|
||||
latencyTimeout: latencyTimeout!,
|
||||
delays: groupDelays.get(group.name),
|
||||
items: ret,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user