Files
clash-proxy/src-tauri/src/feat/clash.rs
Tunglies 355a18e5eb 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
2025-08-26 01:49:51 +08:00

145 lines
4.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use crate::{
config::Config,
core::{handle, tray, CoreManager},
ipc::IpcManager,
logging_error,
process::AsyncHandler,
utils::{logging::Type, resolve},
};
use serde_yaml::{Mapping, Value};
use tauri::Manager;
/// Restart the Clash core
pub async fn restart_clash_core() {
match CoreManager::global().restart_core().await {
Ok(_) => {
handle::Handle::refresh_clash();
handle::Handle::notice_message("set_config::ok", "ok");
}
Err(err) => {
handle::Handle::notice_message("set_config::error", format!("{err}"));
log::error!(target:"app", "{err}");
}
}
}
/// Restart the application
pub async fn restart_app() {
// logging_error!(Type::Core, true, CoreManager::global().stop_core().await);
resolve::resolve_reset_async().await;
handle::Handle::global()
.app_handle()
.map(|app_handle| {
tauri::process::restart(&app_handle.env());
})
.unwrap_or_else(|| {
logging_error!(
Type::System,
false,
"{}",
"Failed to get app handle for restart"
);
});
}
fn after_change_clash_mode() {
AsyncHandler::spawn(move || async {
match IpcManager::global().get_connections().await {
Ok(connections) => {
if let Some(connections_array) = connections["connections"].as_array() {
for connection in connections_array {
if let Some(id) = connection["id"].as_str() {
let _ = IpcManager::global().delete_connection(id).await;
}
}
}
}
Err(err) => {
log::error!(target: "app", "Failed to get connections: {err}");
}
}
});
}
/// Change Clash mode (rule/global/direct/script)
pub async fn change_clash_mode(mode: String) {
let mut mapping = Mapping::new();
mapping.insert(Value::from("mode"), mode.clone().into());
// Convert YAML mapping to JSON Value
let json_value = serde_json::json!({
"mode": mode
});
log::debug!(target: "app", "change clash mode to {mode}");
match IpcManager::global().patch_configs(json_value).await {
Ok(_) => {
// 更新订阅
Config::clash().await.data_mut().patch_config(mapping);
// 分离数据获取和异步调用
let clash_data = Config::clash().await.data_mut().clone();
if clash_data.save_config().await.is_ok() {
handle::Handle::refresh_clash();
logging_error!(Type::Tray, true, tray::Tray::global().update_menu().await);
logging_error!(
Type::Tray,
true,
tray::Tray::global().update_icon(None).await
);
}
let is_auto_close_connection = Config::verge()
.await
.data_mut()
.auto_close_connection
.unwrap_or(false);
if is_auto_close_connection {
after_change_clash_mode();
}
}
Err(err) => log::error!(target: "app", "{err}"),
}
}
/// Test connection delay to a URL
pub async fn test_delay(url: String) -> anyhow::Result<u32> {
use crate::utils::network::{NetworkManager, ProxyType};
use tokio::time::Instant;
let tun_mode = Config::verge()
.await
.latest_ref()
.enable_tun_mode
.unwrap_or(false);
// 如果是TUN模式不使用代理否则使用自身代理
let proxy_type = if !tun_mode {
ProxyType::Localhost
} else {
ProxyType::None
};
let user_agent = Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0".to_string());
let start = Instant::now();
let response = NetworkManager::global()
.get_with_interrupt(&url, proxy_type, Some(10), user_agent, false)
.await;
match response {
Ok(response) => {
log::trace!(target: "app", "test_delay response: {response:#?}");
if response.status().is_success() {
Ok(start.elapsed().as_millis() as u32)
} else {
Ok(10000u32)
}
}
Err(err) => {
log::trace!(target: "app", "test_delay error: {err:#?}");
Err(err)
}
}
}