refactor: activate selected proxies (#7285)

* feat(profiles): add automatic node activation after profile switch

* refactor(use-profiles): simplify patchCurrent logic by always mutating profiles

* refactor(use-profiles): remove unused activateSelected function and related imports

* refactor: rename worker handle to activate selected task

* fix: clippy

* refactor(config): replace log statements with structured logging

* refactor(config): fix incorrect retry logic in profile activation

* feat(profiles): update proxy cache when switching profiles

* docs: update changelog with bug fixes and logic improvements

* refactor(profiles): remove unused imports and redundant cache update
This commit is contained in:
oomeow
2026-07-01 12:47:03 +00:00
committed by GitHub
parent af0518d578
commit c2ddb5c111
5 changed files with 115 additions and 182 deletions
+3 -152
View File
@@ -1,12 +1,5 @@
import { selectNodeForGroup } from 'tauri-plugin-mihomo-api'
import {
calcuProxies,
getProfiles,
patchProfile,
patchProfilesConfig,
} from '@/services/cmds'
import { setCacheData, useQuery } from '@/services/query-client'
import { getProfiles, patchProfile, patchProfilesConfig } from '@/services/cmds'
import { useQuery } from '@/services/query-client'
import { debugLog } from '@/utils/debug'
export const useProfiles = () => {
@@ -70,155 +63,13 @@ export const useProfiles = () => {
const patchCurrent = async (value: Partial<IProfileItem>) => {
if (profiles?.current) {
await patchProfile(profiles.current, value)
if (!value.selected) {
mutateProfiles()
}
}
}
// 根据selected的节点选择
const activateSelected = async (profileOverride?: IProfilesConfig) => {
try {
debugLog('[ActivateSelected] 开始处理代理选择')
const proxiesData = await calcuProxies()
const profileData = profileOverride ?? profiles
if (!profileData || !proxiesData || !profileData.items) {
debugLog('[ActivateSelected] 代理或配置数据不可用,跳过处理')
return
}
const current = profileData.items?.find(
(e) => e && e.uid === profileData.current,
)
if (!current) {
debugLog('[ActivateSelected] 未找到当前profile配置')
return
}
// 检查是否有saved的代理选择
const { selected = [] } = current
if (selected.length === 0) {
debugLog('[ActivateSelected] 当前profile无保存的代理选择,跳过')
return
}
debugLog(
`[ActivateSelected] 当前profile有 ${selected.length} 个代理选择配置`,
)
type SelectedEntry = { name?: string; now?: string }
const selectedMap = Object.fromEntries(
(selected as SelectedEntry[])
.filter(
(each): each is SelectedEntry & { name: string; now: string } =>
each.name != null && each.now != null,
)
.map((each) => [each.name, each.now]),
)
let hasChange = false
const newSelected: typeof selected = []
const { global, groups } = proxiesData
const selectableTypes = new Set([
'Selector',
'URLTest',
'Fallback',
'LoadBalance',
])
// 处理所有代理组
for (const group of [global, ...groups]) {
if (!group) {
continue
}
const { type, name, now } = group
const savedProxy = selectedMap[name]
const availableProxies = Array.isArray(group.all) ? group.all : []
if (!selectableTypes.has(type)) {
if (savedProxy != null || now != null) {
const preferredProxy = now ? now : savedProxy
newSelected.push({ name, now: preferredProxy })
}
continue
}
if (savedProxy == null) {
if (now != null) {
newSelected.push({ name, now })
}
continue
}
const existsInGroup = availableProxies.some((proxy) => {
if (typeof proxy === 'string') {
return proxy === savedProxy
}
return proxy?.name === savedProxy
})
if (!existsInGroup) {
console.warn(
`[ActivateSelected] 保存的代理 ${savedProxy} 不存在于代理组 ${name}`,
)
hasChange = true
newSelected.push({ name, now: now ?? savedProxy })
continue
}
if (savedProxy !== now) {
debugLog(
`[ActivateSelected] 需要切换代理组 ${name}: ${now} -> ${savedProxy}`,
)
hasChange = true
try {
await selectNodeForGroup(name, savedProxy)
} catch (error: unknown) {
console.warn(
`[ActivateSelected] 切换代理组 ${name} 失败:`,
error instanceof Error ? error.message : String(error),
)
}
}
newSelected.push({ name, now: savedProxy })
}
if (!hasChange) {
debugLog('[ActivateSelected] 所有代理选择已经是目标状态,无需更新')
return
}
debugLog(`[ActivateSelected] 完成代理切换,保存新的选择配置`)
try {
await patchProfile(current.uid, { selected: newSelected })
debugLog('[ActivateSelected] 代理选择配置保存成功')
setCacheData(['getProxies'], await calcuProxies())
} catch (error: unknown) {
console.error(
'[ActivateSelected] 保存代理选择配置失败:',
error instanceof Error ? error.message : String(error),
)
}
} catch (error: unknown) {
console.error(
'[ActivateSelected] 处理代理选择失败:',
error instanceof Error ? error.message : String(error),
)
mutateProfiles()
}
}
return {
profiles,
current: profiles?.items?.find((p) => p && p.uid === profiles.current),
activateSelected,
patchProfiles,
patchCurrent,
mutateProfiles,
+8 -25
View File
@@ -1,7 +1,7 @@
import {
closestCenter,
DndContext,
DragEndEvent,
type DragEndEvent,
DragOverlay,
KeyboardSensor,
PointerSensor,
@@ -36,23 +36,23 @@ import {
} from 'react'
import { useTranslation } from 'react-i18next'
import { useLocation } from 'react-router'
import {
closeAllConnections,
selectNodeForGroup,
} from 'tauri-plugin-mihomo-api'
import { closeAllConnections } from 'tauri-plugin-mihomo-api'
import { BasePage, BaseStyledTextField, DialogRef } from '@/components/base'
import {
BasePage,
BaseStyledTextField,
type DialogRef,
} from '@/components/base'
import { ProfileItem } from '@/components/profile/profile-item'
import { ProfileMore } from '@/components/profile/profile-more'
import {
ProfileViewer,
ProfileViewerRef,
type ProfileViewerRef,
} from '@/components/profile/profile-viewer'
import { ConfigViewer } from '@/components/setting/mods/config-viewer'
import { useListen } from '@/hooks/use-listen'
import { useProfiles } from '@/hooks/use-profiles'
import {
calcuProxies,
createProfile,
deleteProfile,
enhanceProfiles,
@@ -67,7 +67,6 @@ import { showNotice } from '@/services/notice-service'
import {
fetchCacheData,
revalidateQueries,
setCacheData,
useQuery,
} from '@/services/query-client'
import {
@@ -466,22 +465,6 @@ const ProfilePage = () => {
return
}
// 选择所记忆的节点
const current = profiles.items?.find((e) => e.uid === profile)
for (const item of current?.selected ?? []) {
if (item.name && item.now) {
try {
await selectNodeForGroup(item.name, item.now)
} catch (err) {
debugLog(
`[Profile] 选择节点失败: ${item.name} -> ${item.now}`,
err,
)
}
}
}
setCacheData(['getProxies'], await calcuProxies())
// 完成切换
await mutateLogs()
closeAllConnections()