mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-18 08:21:34 +08:00
fix: unexpected latency when switching nodes #6363
This commit is contained in:
parent
49fd3b04dc
commit
262b6f8adf
@ -1,20 +1,52 @@
|
|||||||
use super::CmdResult;
|
use super::CmdResult;
|
||||||
|
use crate::core::tray::Tray;
|
||||||
|
use crate::process::AsyncHandler;
|
||||||
use clash_verge_logging::{Type, logging};
|
use clash_verge_logging::{Type, logging};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
static TRAY_SYNC_RUNNING: AtomicBool = AtomicBool::new(false);
|
||||||
|
static TRAY_SYNC_PENDING: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
// TODO: 前端通过 emit 发送更新事件, tray 监听更新事件
|
|
||||||
/// 同步托盘和GUI的代理选择状态
|
/// 同步托盘和GUI的代理选择状态
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn sync_tray_proxy_selection() -> CmdResult<()> {
|
pub async fn sync_tray_proxy_selection() -> CmdResult<()> {
|
||||||
use crate::core::tray::Tray;
|
if TRAY_SYNC_RUNNING
|
||||||
|
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
AsyncHandler::spawn(move || async move {
|
||||||
|
run_tray_sync_loop().await;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
TRAY_SYNC_PENDING.store(true, Ordering::Release);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run_tray_sync_loop() {
|
||||||
|
loop {
|
||||||
match Tray::global().update_menu().await {
|
match Tray::global().update_menu().await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
logging!(info, Type::Cmd, "Tray proxy selection synced successfully");
|
logging!(info, Type::Cmd, "Tray proxy selection synced successfully");
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
logging!(error, Type::Cmd, "Failed to sync tray proxy selection: {e}");
|
logging!(error, Type::Cmd, "Failed to sync tray proxy selection: {e}");
|
||||||
Err(e.to_string().into())
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !TRAY_SYNC_PENDING.swap(false, Ordering::AcqRel) {
|
||||||
|
TRAY_SYNC_RUNNING.store(false, Ordering::Release);
|
||||||
|
|
||||||
|
if TRAY_SYNC_PENDING.swap(false, Ordering::AcqRel)
|
||||||
|
&& TRAY_SYNC_RUNNING
|
||||||
|
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { useLockFn } from "ahooks";
|
import { useCallback, useMemo, useRef } from "react";
|
||||||
import { useCallback, useMemo } from "react";
|
|
||||||
import {
|
import {
|
||||||
closeConnection,
|
closeConnection,
|
||||||
getConnections,
|
getConnections,
|
||||||
@ -34,10 +33,19 @@ interface ProxySelectionOptions {
|
|||||||
enableConnectionCleanup?: boolean;
|
enableConnectionCleanup?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ProxyChangeRequest {
|
||||||
|
groupName: string;
|
||||||
|
proxyName: string;
|
||||||
|
previousProxy?: string;
|
||||||
|
skipConfigSave: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
// 代理选择 Hook
|
// 代理选择 Hook
|
||||||
export const useProxySelection = (options: ProxySelectionOptions = {}) => {
|
export const useProxySelection = (options: ProxySelectionOptions = {}) => {
|
||||||
const { current, patchCurrent } = useProfiles();
|
const { current, patchCurrent } = useProfiles();
|
||||||
const { verge } = useVerge();
|
const { verge } = useVerge();
|
||||||
|
const pendingRequestRef = useRef<ProxyChangeRequest | null>(null);
|
||||||
|
const isProcessingRef = useRef(false);
|
||||||
|
|
||||||
const { onSuccess, onError, enableConnectionCleanup = true } = options;
|
const { onSuccess, onError, enableConnectionCleanup = true } = options;
|
||||||
|
|
||||||
@ -51,17 +59,16 @@ export const useProxySelection = (options: ProxySelectionOptions = {}) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 切换节点
|
// 切换节点
|
||||||
const changeProxy = useLockFn(
|
const syncTraySelection = useCallback(() => {
|
||||||
async (
|
syncTrayProxySelection().catch((error) => {
|
||||||
groupName: string,
|
console.error("[ProxySelection] 托盘状态同步失败:", error);
|
||||||
proxyName: string,
|
});
|
||||||
previousProxy?: string,
|
}, []);
|
||||||
skipConfigSave: boolean = false,
|
|
||||||
) => {
|
const persistSelection = useCallback(
|
||||||
debugLog(`[ProxySelection] 代理切换: ${groupName} -> ${proxyName}`);
|
(groupName: string, proxyName: string, skipConfigSave: boolean) => {
|
||||||
|
if (!current || skipConfigSave) return;
|
||||||
|
|
||||||
try {
|
|
||||||
if (current && !skipConfigSave) {
|
|
||||||
const selected = current.selected ? [...current.selected] : [];
|
const selected = current.selected ? [...current.selected] : [];
|
||||||
const index = selected.findIndex((item) => item.name === groupName);
|
const index = selected.findIndex((item) => item.name === groupName);
|
||||||
|
|
||||||
@ -70,17 +77,28 @@ export const useProxySelection = (options: ProxySelectionOptions = {}) => {
|
|||||||
} else {
|
} else {
|
||||||
selected[index] = { name: groupName, now: proxyName };
|
selected[index] = { name: groupName, now: proxyName };
|
||||||
}
|
}
|
||||||
await patchCurrent({ selected });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
patchCurrent({ selected }).catch((error) => {
|
||||||
|
console.error("[ProxySelection] 保存代理选择失败:", error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[current, patchCurrent],
|
||||||
|
);
|
||||||
|
|
||||||
|
const executeChange = useCallback(
|
||||||
|
async (request: ProxyChangeRequest) => {
|
||||||
|
const { groupName, proxyName, previousProxy, skipConfigSave } = request;
|
||||||
|
debugLog(`[ProxySelection] 代理切换: ${groupName} -> ${proxyName}`);
|
||||||
|
|
||||||
|
try {
|
||||||
await selectNodeForGroup(groupName, proxyName);
|
await selectNodeForGroup(groupName, proxyName);
|
||||||
await syncTrayProxySelection();
|
onSuccess?.();
|
||||||
|
syncTraySelection();
|
||||||
|
persistSelection(groupName, proxyName, skipConfigSave);
|
||||||
debugLog(
|
debugLog(
|
||||||
`[ProxySelection] 代理和状态同步完成: ${groupName} -> ${proxyName}`,
|
`[ProxySelection] 代理和状态同步完成: ${groupName} -> ${proxyName}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
onSuccess?.();
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
config.enableConnectionCleanup &&
|
config.enableConnectionCleanup &&
|
||||||
config.autoCloseConnection &&
|
config.autoCloseConnection &&
|
||||||
@ -96,8 +114,9 @@ export const useProxySelection = (options: ProxySelectionOptions = {}) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await selectNodeForGroup(groupName, proxyName);
|
await selectNodeForGroup(groupName, proxyName);
|
||||||
await syncTrayProxySelection();
|
|
||||||
onSuccess?.();
|
onSuccess?.();
|
||||||
|
syncTraySelection();
|
||||||
|
persistSelection(groupName, proxyName, skipConfigSave);
|
||||||
debugLog(
|
debugLog(
|
||||||
`[ProxySelection] 代理切换回退成功: ${groupName} -> ${proxyName}`,
|
`[ProxySelection] 代理切换回退成功: ${groupName} -> ${proxyName}`,
|
||||||
);
|
);
|
||||||
@ -110,6 +129,43 @@ export const useProxySelection = (options: ProxySelectionOptions = {}) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[config, onError, onSuccess, persistSelection, syncTraySelection],
|
||||||
|
);
|
||||||
|
|
||||||
|
const flushChangeQueue = useCallback(async () => {
|
||||||
|
if (isProcessingRef.current) return;
|
||||||
|
isProcessingRef.current = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (pendingRequestRef.current) {
|
||||||
|
const request = pendingRequestRef.current;
|
||||||
|
pendingRequestRef.current = null;
|
||||||
|
await executeChange(request);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
isProcessingRef.current = false;
|
||||||
|
if (pendingRequestRef.current) {
|
||||||
|
void flushChangeQueue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [executeChange]);
|
||||||
|
|
||||||
|
const changeProxy = useCallback(
|
||||||
|
(
|
||||||
|
groupName: string,
|
||||||
|
proxyName: string,
|
||||||
|
previousProxy?: string,
|
||||||
|
skipConfigSave: boolean = false,
|
||||||
|
) => {
|
||||||
|
pendingRequestRef.current = {
|
||||||
|
groupName,
|
||||||
|
proxyName,
|
||||||
|
previousProxy,
|
||||||
|
skipConfigSave,
|
||||||
|
};
|
||||||
|
void flushChangeQueue();
|
||||||
|
},
|
||||||
|
[flushChangeQueue],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSelectChange = useCallback(
|
const handleSelectChange = useCallback(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user