mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 17:15:38 +08:00
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:
@@ -51,6 +51,7 @@
|
|||||||
- 优化重启应用的资源清理逻辑
|
- 优化重启应用的资源清理逻辑
|
||||||
- 优化前端数据刷新
|
- 优化前端数据刷新
|
||||||
- 优化流量采样和数据处理
|
- 优化流量采样和数据处理
|
||||||
|
- 优化应用重启/退出时的资源清理性能, 大幅缩短执行时间
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use crate::{
|
|||||||
validate::CoreConfigValidator,
|
validate::CoreConfigValidator,
|
||||||
},
|
},
|
||||||
enhance,
|
enhance,
|
||||||
|
process::AsyncHandler,
|
||||||
utils::{dirs, help},
|
utils::{dirs, help},
|
||||||
};
|
};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
@@ -213,17 +214,27 @@ impl Config {
|
|||||||
// 升级草稿为正式数据,并写入文件。避免用户行为丢失。
|
// 升级草稿为正式数据,并写入文件。避免用户行为丢失。
|
||||||
// 仅在应用退出、重启、关机监听事件启用
|
// 仅在应用退出、重启、关机监听事件启用
|
||||||
pub async fn apply_all_and_save_file() {
|
pub async fn apply_all_and_save_file() {
|
||||||
|
logging!(info, Type::Config, "save all draft data");
|
||||||
|
let save_clash_task = AsyncHandler::spawn(|| async {
|
||||||
let clash = Self::clash().await;
|
let clash = Self::clash().await;
|
||||||
clash.apply();
|
clash.apply();
|
||||||
logging_error!(Type::Config, clash.data_arc().save_config().await);
|
logging_error!(Type::Config, clash.data_arc().save_config().await);
|
||||||
|
});
|
||||||
|
|
||||||
|
let save_verge_task = AsyncHandler::spawn(|| async {
|
||||||
let verge = Self::verge().await;
|
let verge = Self::verge().await;
|
||||||
verge.apply();
|
verge.apply();
|
||||||
logging_error!(Type::Config, verge.data_arc().save_file().await);
|
logging_error!(Type::Config, verge.data_arc().save_file().await);
|
||||||
|
});
|
||||||
|
|
||||||
|
let save_profiles_task = AsyncHandler::spawn(|| async {
|
||||||
let profiles = Self::profiles().await;
|
let profiles = Self::profiles().await;
|
||||||
profiles.apply();
|
profiles.apply();
|
||||||
logging_error!(Type::Config, profiles.data_arc().save_file().await);
|
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clash_verge_logging::{Type, logging, logging_error};
|
use clash_verge_logging::{Type, logging, logging_error};
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
use parking_lot::Mutex;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use scopeguard::defer;
|
use scopeguard::defer;
|
||||||
use smartstring::alias::String;
|
use smartstring::alias::String;
|
||||||
@@ -23,6 +25,10 @@ use tauri_plugin_autostart::ManagerExt as _;
|
|||||||
pub struct Sysopt {
|
pub struct Sysopt {
|
||||||
update_sysproxy: AtomicBool,
|
update_sysproxy: AtomicBool,
|
||||||
reset_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>>,
|
guard: Arc<RwLock<GuardMonitor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +37,10 @@ impl Default for Sysopt {
|
|||||||
Self {
|
Self {
|
||||||
update_sysproxy: AtomicBool::new(false),
|
update_sysproxy: AtomicBool::new(false),
|
||||||
reset_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(
|
guard: Arc::new(RwLock::new(GuardMonitor::new(
|
||||||
GuardType::None,
|
GuardType::None,
|
||||||
Duration::from_secs(30),
|
Duration::from_secs(30),
|
||||||
@@ -185,23 +195,25 @@ impl Sysopt {
|
|||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
{
|
{
|
||||||
let mut sys = Sysproxy {
|
// 先 await, 避免持有锁导致的 Send 问题
|
||||||
enable: false,
|
let bypass = get_bypass().await;
|
||||||
host: proxy_host.clone().into(),
|
|
||||||
port,
|
let mut sys = self.sysproxy.lock();
|
||||||
bypass: get_bypass().await.into(),
|
sys.enable = false;
|
||||||
};
|
sys.host = proxy_host.clone().into();
|
||||||
let mut auto = Autoproxy {
|
sys.port = port;
|
||||||
enable: false,
|
sys.bypass = bypass.into();
|
||||||
url: format!("http://{proxy_host}:{pac_port}/commands/pac"),
|
|
||||||
};
|
let mut auto = self.autoproxy.lock();
|
||||||
|
auto.enable = false;
|
||||||
|
auto.url = format!("http://{proxy_host}:{pac_port}/commands/pac");
|
||||||
|
|
||||||
if !sys_enable {
|
if !sys_enable {
|
||||||
sys.set_system_proxy()?;
|
sys.set_system_proxy()?;
|
||||||
auto.set_auto_proxy()?;
|
auto.set_auto_proxy()?;
|
||||||
self.access_guard()
|
self.access_guard()
|
||||||
.write()
|
.write()
|
||||||
.set_guard_type(GuardType::Sysproxy(sys));
|
.set_guard_type(GuardType::Sysproxy(sys.clone()));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +224,7 @@ impl Sysopt {
|
|||||||
auto.set_auto_proxy()?;
|
auto.set_auto_proxy()?;
|
||||||
self.access_guard()
|
self.access_guard()
|
||||||
.write()
|
.write()
|
||||||
.set_guard_type(GuardType::Autoproxy(auto));
|
.set_guard_type(GuardType::Autoproxy(auto.clone()));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,9 +233,11 @@ impl Sysopt {
|
|||||||
sys.enable = true;
|
sys.enable = true;
|
||||||
auto.set_auto_proxy()?;
|
auto.set_auto_proxy()?;
|
||||||
sys.set_system_proxy()?;
|
sys.set_system_proxy()?;
|
||||||
|
drop(auto);
|
||||||
self.access_guard()
|
self.access_guard()
|
||||||
.write()
|
.write()
|
||||||
.set_guard_type(GuardType::Sysproxy(sys));
|
.set_guard_type(GuardType::Sysproxy(sys.clone()));
|
||||||
|
drop(sys);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,32 +296,13 @@ impl Sysopt {
|
|||||||
//直接关闭所有代理
|
//直接关闭所有代理
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
{
|
{
|
||||||
let mut sysproxy: Sysproxy = match Sysproxy::get_system_proxy() {
|
let mut sysproxy = self.sysproxy.lock();
|
||||||
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()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sysproxy.enable = false;
|
sysproxy.enable = false;
|
||||||
|
sysproxy.set_system_proxy()?;
|
||||||
|
drop(sysproxy);
|
||||||
|
let mut autoproxy = self.autoproxy.lock();
|
||||||
autoproxy.enable = false;
|
autoproxy.enable = false;
|
||||||
autoproxy.set_auto_proxy()?;
|
autoproxy.set_auto_proxy()?;
|
||||||
sysproxy.set_system_proxy()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ pub async fn restart_clash_core() {
|
|||||||
/// Restart the application
|
/// Restart the application
|
||||||
pub async fn restart_app() {
|
pub async fn restart_app() {
|
||||||
logging!(debug, Type::System, "启动重启应用流程");
|
logging!(debug, Type::System, "启动重启应用流程");
|
||||||
utils::server::shutdown_embedded_server();
|
|
||||||
Config::apply_all_and_save_file().await;
|
|
||||||
|
|
||||||
// 设置退出标志
|
// 设置退出标志
|
||||||
handle::Handle::global().set_is_exiting();
|
handle::Handle::global().set_is_exiting();
|
||||||
|
|
||||||
|
utils::server::shutdown_embedded_server();
|
||||||
|
Config::apply_all_and_save_file().await;
|
||||||
|
|
||||||
logging!(info, Type::System, "开始异步清理资源");
|
logging!(info, Type::System, "开始异步清理资源");
|
||||||
let cleanup_result = clean_async().await;
|
let cleanup_result = clean_async().await;
|
||||||
|
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ async fn open_or_close_dashboard_internal() {
|
|||||||
|
|
||||||
pub async fn quit() {
|
pub async fn quit() {
|
||||||
logging!(debug, Type::System, "启动退出流程");
|
logging!(debug, Type::System, "启动退出流程");
|
||||||
utils::server::shutdown_embedded_server();
|
|
||||||
Config::apply_all_and_save_file().await;
|
|
||||||
|
|
||||||
// 设置退出标志
|
// 设置退出标志
|
||||||
handle::Handle::global().set_is_exiting();
|
handle::Handle::global().set_is_exiting();
|
||||||
|
|
||||||
|
utils::server::shutdown_embedded_server();
|
||||||
|
Config::apply_all_and_save_file().await;
|
||||||
|
|
||||||
logging!(info, Type::System, "开始异步清理资源");
|
logging!(info, Type::System, "开始异步清理资源");
|
||||||
let cleanup_result = clean_async().await;
|
let cleanup_result = clean_async().await;
|
||||||
|
|
||||||
@@ -43,51 +43,8 @@ pub async fn quit() {
|
|||||||
pub async fn clean_async() -> bool {
|
pub async fn clean_async() -> bool {
|
||||||
logging!(info, Type::System, "开始执行异步清理操作...");
|
logging!(info, Type::System, "开始执行异步清理操作...");
|
||||||
|
|
||||||
// 1. 处理TUN模式
|
// 重置系统代理
|
||||||
let tun_task = async {
|
let proxy_task = tokio::task::spawn(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 {
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
use sysproxy::{Autoproxy, Sysproxy};
|
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")]
|
#[cfg(target_os = "windows")]
|
||||||
let stop_timeout = Duration::from_secs(2);
|
let stop_timeout = Duration::from_secs(2);
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
@@ -227,11 +218,11 @@ pub async fn clean_async() -> bool {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
// 4. DNS恢复(仅macOS)
|
// DNS恢复(仅macOS)
|
||||||
|
let dns_task = tokio::task::spawn(async {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let dns_task = async {
|
|
||||||
match timeout(
|
match timeout(
|
||||||
Duration::from_millis(1000),
|
Duration::from_millis(1000),
|
||||||
crate::utils::resolve::dns::restore_public_dns(),
|
crate::utils::resolve::dns::restore_public_dns(),
|
||||||
@@ -247,22 +238,23 @@ pub async fn clean_async() -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
let dns_task = async { true };
|
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!(
|
logging!(
|
||||||
info,
|
info,
|
||||||
Type::System,
|
Type::System,
|
||||||
"异步关闭操作完成 - TUN: {}, 代理: {}, 核心: {}, DNS: {}, 总体: {}",
|
"异步关闭操作完成 - 代理: {}, 核心: {}, DNS: {}, 总体: {}",
|
||||||
tun_success,
|
|
||||||
proxy_success,
|
proxy_success,
|
||||||
core_success,
|
core_success,
|
||||||
dns_success,
|
dns_success,
|
||||||
|
|||||||
@@ -429,7 +429,9 @@ pub fn run() {
|
|||||||
}
|
}
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
tauri::RunEvent::Exit => AsyncHandler::block_on(async {
|
tauri::RunEvent::Exit => AsyncHandler::block_on(async {
|
||||||
|
if !handle::Handle::global().is_exiting() {
|
||||||
feat::quit().await;
|
feat::quit().await;
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
tauri::RunEvent::ExitRequested { api, code, .. } => {
|
tauri::RunEvent::ExitRequested { api, code, .. } => {
|
||||||
AsyncHandler::block_on(async {
|
AsyncHandler::block_on(async {
|
||||||
|
|||||||
Reference in New Issue
Block a user