perf: spawn clean task (#5595)

* perf: spawn task

* perf: spawn task to save draft date

* perf: store proxy client

* chore: update

* perf: reduce handle quit on macOS

* chore: clippy

* docs: update Changelog.md

* chore: update
This commit is contained in:
oomeow
2025-11-28 21:12:34 +08:00
committed by GitHub
parent 683667f8ae
commit 6456c597ed
6 changed files with 114 additions and 113 deletions

View File

@@ -9,6 +9,7 @@ use crate::{
validate::CoreConfigValidator,
},
enhance,
process::AsyncHandler,
utils::{dirs, help},
};
use anyhow::{Result, anyhow};
@@ -213,17 +214,27 @@ impl Config {
// 升级草稿为正式数据,并写入文件。避免用户行为丢失。
// 仅在应用退出、重启、关机监听事件启用
pub async fn apply_all_and_save_file() {
let clash = Self::clash().await;
clash.apply();
logging_error!(Type::Config, clash.data_arc().save_config().await);
logging!(info, Type::Config, "save all draft data");
let save_clash_task = AsyncHandler::spawn(|| async {
let clash = Self::clash().await;
clash.apply();
logging_error!(Type::Config, clash.data_arc().save_config().await);
});
let verge = Self::verge().await;
verge.apply();
logging_error!(Type::Config, verge.data_arc().save_file().await);
let save_verge_task = AsyncHandler::spawn(|| async {
let verge = Self::verge().await;
verge.apply();
logging_error!(Type::Config, verge.data_arc().save_file().await);
});
let profiles = Self::profiles().await;
profiles.apply();
logging_error!(Type::Config, profiles.data_arc().save_file().await);
let save_profiles_task = AsyncHandler::spawn(|| async {
let profiles = Self::profiles().await;
profiles.apply();
logging_error!(Type::Config, profiles.data_arc().save_file().await);
});
let _ = tokio::join!(save_clash_task, save_verge_task, save_profiles_task);
logging!(info, Type::Config, "save all draft data finished");
}
}

View File

@@ -7,6 +7,8 @@ use crate::{
};
use anyhow::Result;
use clash_verge_logging::{Type, logging, logging_error};
#[cfg(not(target_os = "windows"))]
use parking_lot::Mutex;
use parking_lot::RwLock;
use scopeguard::defer;
use smartstring::alias::String;
@@ -23,6 +25,10 @@ use tauri_plugin_autostart::ManagerExt as _;
pub struct Sysopt {
update_sysproxy: AtomicBool,
reset_sysproxy: AtomicBool,
#[cfg(not(target_os = "windows"))]
sysproxy: Arc<Mutex<Sysproxy>>,
#[cfg(not(target_os = "windows"))]
autoproxy: Arc<Mutex<Autoproxy>>,
guard: Arc<RwLock<GuardMonitor>>,
}
@@ -31,6 +37,10 @@ impl Default for Sysopt {
Self {
update_sysproxy: AtomicBool::new(false),
reset_sysproxy: AtomicBool::new(false),
#[cfg(not(target_os = "windows"))]
sysproxy: Arc::new(Mutex::new(Sysproxy::default())),
#[cfg(not(target_os = "windows"))]
autoproxy: Arc::new(Mutex::new(Autoproxy::default())),
guard: Arc::new(RwLock::new(GuardMonitor::new(
GuardType::None,
Duration::from_secs(30),
@@ -185,23 +195,25 @@ impl Sysopt {
#[cfg(not(target_os = "windows"))]
{
let mut sys = Sysproxy {
enable: false,
host: proxy_host.clone().into(),
port,
bypass: get_bypass().await.into(),
};
let mut auto = Autoproxy {
enable: false,
url: format!("http://{proxy_host}:{pac_port}/commands/pac"),
};
// 先 await, 避免持有锁导致的 Send 问题
let bypass = get_bypass().await;
let mut sys = self.sysproxy.lock();
sys.enable = false;
sys.host = proxy_host.clone().into();
sys.port = port;
sys.bypass = bypass.into();
let mut auto = self.autoproxy.lock();
auto.enable = false;
auto.url = format!("http://{proxy_host}:{pac_port}/commands/pac");
if !sys_enable {
sys.set_system_proxy()?;
auto.set_auto_proxy()?;
self.access_guard()
.write()
.set_guard_type(GuardType::Sysproxy(sys));
.set_guard_type(GuardType::Sysproxy(sys.clone()));
return Ok(());
}
@@ -212,7 +224,7 @@ impl Sysopt {
auto.set_auto_proxy()?;
self.access_guard()
.write()
.set_guard_type(GuardType::Autoproxy(auto));
.set_guard_type(GuardType::Autoproxy(auto.clone()));
return Ok(());
}
@@ -221,9 +233,11 @@ impl Sysopt {
sys.enable = true;
auto.set_auto_proxy()?;
sys.set_system_proxy()?;
drop(auto);
self.access_guard()
.write()
.set_guard_type(GuardType::Sysproxy(sys));
.set_guard_type(GuardType::Sysproxy(sys.clone()));
drop(sys);
return Ok(());
}
}
@@ -282,32 +296,13 @@ impl Sysopt {
//直接关闭所有代理
#[cfg(not(target_os = "windows"))]
{
let mut sysproxy: Sysproxy = match Sysproxy::get_system_proxy() {
Ok(sp) => sp,
Err(e) => {
logging!(
warn,
Type::Core,
"Warning: 重置代理时获取系统代理配置失败: {e}, 使用默认配置"
);
Sysproxy::default()
}
};
let mut autoproxy = match Autoproxy::get_auto_proxy() {
Ok(ap) => ap,
Err(e) => {
logging!(
warn,
Type::Core,
"Warning: 重置代理时获取自动代理配置失败: {e}, 使用默认配置"
);
Autoproxy::default()
}
};
let mut sysproxy = self.sysproxy.lock();
sysproxy.enable = false;
sysproxy.set_system_proxy()?;
drop(sysproxy);
let mut autoproxy = self.autoproxy.lock();
autoproxy.enable = false;
autoproxy.set_auto_proxy()?;
sysproxy.set_system_proxy()?;
}
#[cfg(target_os = "windows")]

View File

@@ -26,12 +26,12 @@ pub async fn restart_clash_core() {
/// Restart the application
pub async fn restart_app() {
logging!(debug, Type::System, "启动重启应用流程");
utils::server::shutdown_embedded_server();
Config::apply_all_and_save_file().await;
// 设置退出标志
handle::Handle::global().set_is_exiting();
utils::server::shutdown_embedded_server();
Config::apply_all_and_save_file().await;
logging!(info, Type::System, "开始异步清理资源");
let cleanup_result = clean_async().await;

View File

@@ -20,12 +20,12 @@ async fn open_or_close_dashboard_internal() {
pub async fn quit() {
logging!(debug, Type::System, "启动退出流程");
utils::server::shutdown_embedded_server();
Config::apply_all_and_save_file().await;
// 设置退出标志
handle::Handle::global().set_is_exiting();
utils::server::shutdown_embedded_server();
Config::apply_all_and_save_file().await;
logging!(info, Type::System, "开始异步清理资源");
let cleanup_result = clean_async().await;
@@ -43,51 +43,8 @@ pub async fn quit() {
pub async fn clean_async() -> bool {
logging!(info, Type::System, "开始执行异步清理操作...");
// 1. 处理TUN模式
let tun_task = async {
let tun_enabled = Config::verge()
.await
.data_arc()
.enable_tun_mode
.unwrap_or(false);
if !tun_enabled {
return true;
}
let disable_tun = serde_json::json!({ "tun": { "enable": false } });
logging!(info, Type::System, "send disable tun request to mihomo");
match timeout(
Duration::from_millis(1000),
handle::Handle::mihomo()
.await
.patch_base_config(&disable_tun),
)
.await
{
Ok(Ok(_)) => {
logging!(info, Type::Window, "TUN模式已禁用");
true
}
Ok(Err(e)) => {
logging!(warn, Type::Window, "Warning: 禁用TUN模式失败: {e}");
// 超时不阻塞退出
true
}
Err(_) => {
logging!(
warn,
Type::Window,
"Warning: 禁用TUN模式超时可能系统正在关机继续退出流程"
);
true
}
}
};
// 2. 系统代理重置
let proxy_task = async {
// 重置系统代理
let proxy_task = tokio::task::spawn(async {
#[cfg(target_os = "windows")]
{
use sysproxy::{Autoproxy, Sysproxy};
@@ -203,10 +160,44 @@ pub async fn clean_async() -> bool {
}
}
}
};
});
// 关闭 Tun 模式 + 停止核心服务
let core_task = tokio::task::spawn(async {
logging!(info, Type::System, "disable tun");
let tun_enabled = Config::verge()
.await
.data_arc()
.enable_tun_mode
.unwrap_or(false);
if tun_enabled {
let disable_tun = serde_json::json!({ "tun": { "enable": false } });
logging!(info, Type::System, "send disable tun request to mihomo");
match timeout(
Duration::from_millis(1000),
handle::Handle::mihomo()
.await
.patch_base_config(&disable_tun),
)
.await
{
Ok(Ok(_)) => {
logging!(info, Type::Window, "TUN模式已禁用");
}
Ok(Err(e)) => {
logging!(warn, Type::Window, "Warning: 禁用TUN模式失败: {e}");
}
Err(_) => {
logging!(
warn,
Type::Window,
"Warning: 禁用TUN模式超时可能系统正在关机继续退出流程"
);
}
}
}
// 3. 核心服务停止
let core_task = async {
#[cfg(target_os = "windows")]
let stop_timeout = Duration::from_secs(2);
#[cfg(not(target_os = "windows"))]
@@ -227,11 +218,11 @@ pub async fn clean_async() -> bool {
true
}
}
};
});
// 4. DNS恢复仅macOS
#[cfg(target_os = "macos")]
let dns_task = async {
// DNS恢复仅macOS
let dns_task = tokio::task::spawn(async {
#[cfg(target_os = "macos")]
match timeout(
Duration::from_millis(1000),
crate::utils::resolve::dns::restore_public_dns(),
@@ -247,22 +238,23 @@ pub async fn clean_async() -> bool {
false
}
}
};
#[cfg(not(target_os = "macos"))]
true
});
#[cfg(not(target_os = "macos"))]
let dns_task = async { true };
let tun_success = tun_task.await;
// 并行执行清理任务
let (proxy_success, core_success, dns_success) = tokio::join!(proxy_task, core_task, dns_task);
let (proxy_result, core_result, dns_result) = tokio::join!(proxy_task, core_task, dns_task);
let all_success = tun_success && proxy_success && core_success && dns_success;
let proxy_success = proxy_result.unwrap_or_default();
let core_success = core_result.unwrap_or_default();
let dns_success = dns_result.unwrap_or_default();
let all_success = proxy_success && core_success && dns_success;
logging!(
info,
Type::System,
"异步关闭操作完成 - TUN: {}, 代理: {}, 核心: {}, DNS: {}, 总体: {}",
tun_success,
"异步关闭操作完成 - 代理: {}, 核心: {}, DNS: {}, 总体: {}",
proxy_success,
core_success,
dns_success,

View File

@@ -429,7 +429,9 @@ pub fn run() {
}
#[cfg(target_os = "macos")]
tauri::RunEvent::Exit => AsyncHandler::block_on(async {
feat::quit().await;
if !handle::Handle::global().is_exiting() {
feat::quit().await;
}
}),
tauri::RunEvent::ExitRequested { api, code, .. } => {
AsyncHandler::block_on(async {