refactor(async): migrate from sync-blocking async execution to true async with unified AsyncHandler::spawn (#4502)

* feat: replace all tokio::spawn with unified AsyncHandler::spawn

- 🚀 Core Improvements:
  * Replace all tokio::spawn calls with AsyncHandler::spawn for unified Tauri async task management
  * Prioritize converting sync functions to async functions to reduce spawn usage
  * Use .await directly in async contexts instead of spawn

- 🔧 Major Changes:
  * core/hotkey.rs: Use AsyncHandler::spawn for hotkey callback functions
  * module/lightweight.rs: Async lightweight mode switching
  * feat/window.rs: Convert window operation functions to async, use .await internally
  * feat/proxy.rs, feat/clash.rs: Async proxy and mode switching functions
  * lib.rs: Window focus handling with AsyncHandler::spawn
  * core/tray/mod.rs: Complete async tray event handling

-  Technical Advantages:
  * Unified task tracking and debugging capabilities (via tokio-trace feature)
  * Better error handling and task management
  * Consistency with Tauri runtime
  * Reduced async boundaries for better performance

- 🧪 Verification:
  * Compilation successful with 0 errors, 0 warnings
  * Maintains complete original functionality
  * Optimized async execution flow

* feat: complete tokio fs migration and replace tokio::spawn with AsyncHandler

🚀 Major achievements:
- Migrate 8 core modules from std::fs to tokio::fs
- Create 6 Send-safe wrapper functions using spawn_blocking pattern
- Replace all tokio::spawn calls with AsyncHandler::spawn for unified async task management
- Solve all 19 Send trait compilation errors through innovative spawn_blocking architecture

🔧 Core changes:
- config/profiles.rs: Add profiles_*_safe functions to handle Send trait constraints
- cmd/profile.rs: Update all Tauri commands to use Send-safe operations
- config/prfitem.rs: Replace append_item calls with profiles_append_item_safe
- utils/help.rs: Convert YAML operations to async (read_yaml, save_yaml)
- Multiple modules: Replace tokio::task::spawn_blocking with AsyncHandler::spawn_blocking

 Technical innovations:
- spawn_blocking wrapper pattern resolves parking_lot RwLock Send trait conflicts
- Maintain parking_lot performance while achieving Tauri async command compatibility
- Preserve backwards compatibility with gradual migration strategy

🎯 Results:
- Zero compilation errors
- Zero warnings
- All async file operations working correctly
- Complete Send trait compliance for Tauri commands

* feat: refactor app handle and command functions to use async/await for improved performance

* feat: update async handling in profiles and logging functions for improved error handling and performance

* fix: update TRACE_MINI_SIZE constant to improve task logging threshold

* fix(windows): convert service management functions to async for improved performance

* fix: convert service management functions to async for improved responsiveness

* fix(ubuntu): convert install and reinstall service functions to async for improved performance

* fix(linux): convert uninstall_service function to async for improved performance

* fix: convert uninstall_service call to async for improved performance

* fix: convert file and directory creation calls to async for improved performance

* fix: convert hotkey functions to async for improved responsiveness

* chore: update UPDATELOG.md for v2.4.1 with major improvements and performance optimizations
This commit is contained in:
Tunglies
2025-08-26 01:49:51 +08:00
committed by GitHub
parent 4598c805eb
commit 355a18e5eb
47 changed files with 2127 additions and 1809 deletions

View File

@@ -137,25 +137,25 @@ impl CoreManager {
Ok(false)
}
/// 使用默认配置
pub fn use_default_config(&self, msg_type: &str, msg_content: &str) -> Result<()> {
pub async fn use_default_config(&self, msg_type: &str, msg_content: &str) -> Result<()> {
let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG);
*Config::runtime().draft_mut() = Box::new(IRuntime {
config: Some(Config::clash().latest_ref().0.clone()),
// Extract clash config before async operations
let clash_config = Config::clash().await.latest_ref().0.clone();
*Config::runtime().await.draft_mut() = Box::new(IRuntime {
config: Some(clash_config.clone()),
exists_keys: vec![],
chain_logs: Default::default(),
});
help::save_yaml(
&runtime_path,
&Config::clash().latest_ref().0,
Some("# Clash Verge Runtime"),
)?;
help::save_yaml(&runtime_path, &clash_config, Some("# Clash Verge Runtime")).await?;
handle::Handle::notice_message(msg_type, msg_content);
Ok(())
}
/// 验证运行时配置
pub async fn validate_config(&self) -> Result<(bool, String)> {
logging!(info, Type::Config, true, "生成临时配置文件用于验证");
let config_path = Config::generate_file(ConfigType::Check)?;
let config_path = Config::generate_file(ConfigType::Check).await?;
let config_path = dirs::path_to_str(&config_path)?;
self.validate_config_internal(config_path).await
}
@@ -248,7 +248,7 @@ impl CoreManager {
config_path
);
let clash_core = Config::verge().latest_ref().get_valid_clash_core();
let clash_core = Config::verge().await.latest_ref().get_valid_clash_core();
logging!(info, Type::Config, true, "使用内核: {}", clash_core);
let app_handle = handle::Handle::global().app_handle().ok_or_else(|| {
@@ -388,7 +388,7 @@ impl CoreManager {
// 1. 先生成新的配置内容
logging!(info, Type::Config, true, "生成新的配置内容");
Config::generate()?;
Config::generate().await?;
// 2. 验证配置
match self.validate_config().await {
@@ -396,18 +396,18 @@ impl CoreManager {
logging!(info, Type::Config, true, "配置验证通过");
// 4. 验证通过后,生成正式的运行时配置
logging!(info, Type::Config, true, "生成运行时配置");
let run_path = Config::generate_file(ConfigType::Run)?;
let run_path = Config::generate_file(ConfigType::Run).await?;
logging_error!(Type::Config, true, self.put_configs_force(run_path).await);
Ok((true, "something".into()))
}
Ok((false, error_msg)) => {
logging!(warn, Type::Config, true, "配置验证失败: {}", error_msg);
Config::runtime().discard();
Config::runtime().await.discard();
Ok((false, error_msg))
}
Err(e) => {
logging!(warn, Type::Config, true, "验证过程发生错误: {}", e);
Config::runtime().discard();
Config::runtime().await.discard();
Err(e)
}
}
@@ -420,13 +420,13 @@ impl CoreManager {
});
match IpcManager::global().put_configs_force(run_path_str?).await {
Ok(_) => {
Config::runtime().apply();
Config::runtime().await.apply();
logging!(info, Type::Core, true, "Configuration updated successfully");
Ok(())
}
Err(e) => {
let msg = e.to_string();
Config::runtime().discard();
Config::runtime().await.discard();
logging_error!(Type::Core, true, "Failed to update configuration: {}", msg);
Err(msg)
}
@@ -735,13 +735,13 @@ impl CoreManager {
}
}
fn start_core_by_sidecar(&self) -> Result<()> {
async fn start_core_by_sidecar(&self) -> Result<()> {
logging!(trace, Type::Core, true, "Running core by sidecar");
let config_file = &Config::generate_file(ConfigType::Run)?;
let config_file = &Config::generate_file(ConfigType::Run).await?;
let app_handle = handle::Handle::global()
.app_handle()
.ok_or(anyhow::anyhow!("failed to get app handle"))?;
let clash_core = Config::verge().latest_ref().get_valid_clash_core();
let clash_core = Config::verge().await.latest_ref().get_valid_clash_core();
let config_dir = dirs::app_home_dir()?;
let service_log_dir = dirs::app_home_dir()?.join("logs").join("service");
@@ -815,7 +815,7 @@ impl CoreManager {
impl CoreManager {
async fn start_core_by_service(&self) -> Result<()> {
logging!(trace, Type::Core, true, "Running core by service");
let config_file = &Config::generate_file(ConfigType::Run)?;
let config_file = &Config::generate_file(ConfigType::Run).await?;
service::run_core_by_service(config_file).await?;
self.set_running_mode(RunningMode::Service);
Ok(())
@@ -845,7 +845,7 @@ impl CoreManager {
async fn attempt_service_init(&self) -> Result<()> {
if service::check_service_needs_reinstall().await {
logging!(info, Type::Core, true, "服务版本不匹配或状态异常,执行重装");
if let Err(e) = service::reinstall_service() {
if let Err(e) = service::reinstall_service().await {
logging!(
warn,
Type::Core,
@@ -868,11 +868,11 @@ impl CoreManager {
e
);
// 确保 prefer_sidecar 在 start_core_by_service 失败时也被设置
let mut state = service::ServiceState::get();
let mut state = service::ServiceState::get().await;
if !state.prefer_sidecar {
state.prefer_sidecar = true;
state.last_error = Some(format!("通过服务启动核心失败: {e}"));
if let Err(save_err) = state.save() {
if let Err(save_err) = state.save().await {
logging!(
error,
Type::Core,
@@ -941,7 +941,7 @@ impl CoreManager {
"核心未通过服务模式启动执行Sidecar回退或首次安装逻辑"
);
let service_state = service::ServiceState::get();
let service_state = service::ServiceState::get().await;
if service_state.prefer_sidecar {
logging!(
@@ -950,7 +950,7 @@ impl CoreManager {
true,
"用户偏好Sidecar模式或先前服务启动失败使用Sidecar模式启动"
);
self.start_core_by_sidecar()?;
self.start_core_by_sidecar().await?;
// 如果 sidecar 启动成功,我们可以认为核心初始化流程到此结束
// 后续的 Tray::global().subscribe_traffic().await 仍然会执行
} else {
@@ -962,13 +962,13 @@ impl CoreManager {
true,
"无服务安装记录 (首次运行或状态重置),尝试安装服务"
);
match service::install_service() {
match service::install_service().await {
Ok(_) => {
logging!(info, Type::Core, true, "服务安装成功(首次尝试)");
let mut new_state = service::ServiceState::default();
new_state.record_install();
new_state.prefer_sidecar = false;
new_state.save()?;
new_state.save().await?;
if service::is_service_available().await.is_ok() {
logging!(info, Type::Core, true, "新安装的服务可用,尝试启动");
@@ -981,12 +981,12 @@ impl CoreManager {
true,
"新安装的服务启动失败回退到Sidecar模式"
);
let mut final_state = service::ServiceState::get();
let mut final_state = service::ServiceState::get().await;
final_state.prefer_sidecar = true;
final_state.last_error =
Some("Newly installed service failed to start".to_string());
final_state.save()?;
self.start_core_by_sidecar()?;
final_state.save().await?;
self.start_core_by_sidecar().await?;
}
} else {
logging!(
@@ -995,14 +995,14 @@ impl CoreManager {
true,
"服务安装成功但未能连接/立即可用回退到Sidecar模式"
);
let mut final_state = service::ServiceState::get();
let mut final_state = service::ServiceState::get().await;
final_state.prefer_sidecar = true;
final_state.last_error = Some(
"Newly installed service not immediately available/connectable"
.to_string(),
);
final_state.save()?;
self.start_core_by_sidecar()?;
final_state.save().await?;
self.start_core_by_sidecar().await?;
}
}
Err(err) => {
@@ -1012,8 +1012,8 @@ impl CoreManager {
prefer_sidecar: true,
..Default::default()
};
new_state.save()?;
self.start_core_by_sidecar()?;
new_state.save().await?;
self.start_core_by_sidecar().await?;
}
}
} else {
@@ -1026,7 +1026,7 @@ impl CoreManager {
true,
"有服务安装记录但服务不可用/未启动强制切换到Sidecar模式"
);
let mut final_state = service::ServiceState::get();
let mut final_state = service::ServiceState::get().await;
if !final_state.prefer_sidecar {
logging!(
warn,
@@ -1040,9 +1040,9 @@ impl CoreManager {
"Service startup failed or unavailable before sidecar fallback"
.to_string()
}));
final_state.save()?;
final_state.save().await?;
}
self.start_core_by_sidecar()?;
self.start_core_by_sidecar().await?;
}
}
}
@@ -1067,13 +1067,13 @@ impl CoreManager {
pub async fn start_core(&self) -> Result<()> {
if service::is_service_available().await.is_ok() {
if service::check_service_needs_reinstall().await {
service::reinstall_service()?;
service::reinstall_service().await?;
}
logging!(info, Type::Core, true, "服务可用,使用服务模式启动");
self.start_core_by_service().await?;
} else {
// 服务不可用,检查用户偏好
let service_state = service::ServiceState::get();
let service_state = service::ServiceState::get().await;
if service_state.prefer_sidecar {
logging!(
info,
@@ -1081,10 +1081,10 @@ impl CoreManager {
true,
"服务不可用根据用户偏好使用Sidecar模式"
);
self.start_core_by_sidecar()?;
self.start_core_by_sidecar().await?;
} else {
logging!(info, Type::Core, true, "服务不可用使用Sidecar模式");
self.start_core_by_sidecar()?;
self.start_core_by_sidecar().await?;
}
}
Ok(())
@@ -1125,11 +1125,14 @@ impl CoreManager {
return Err(error_message);
}
Config::verge().draft_mut().clash_core = clash_core.clone();
Config::verge().apply();
logging_error!(Type::Core, true, Config::verge().latest_ref().save_file());
Config::verge().await.draft_mut().clash_core = clash_core.clone();
Config::verge().await.apply();
let run_path = Config::generate_file(ConfigType::Run).map_err(|e| {
// 分离数据获取和异步调用避免Send问题
let verge_data = Config::verge().await.latest_ref().clone();
logging_error!(Type::Core, true, verge_data.save_file().await);
let run_path = Config::generate_file(ConfigType::Run).await.map_err(|e| {
let msg = e.to_string();
logging_error!(Type::Core, true, "{}", msg);
msg