From b6a6f5f4345412193a38422fff9670fe899b3ba5 Mon Sep 17 00:00:00 2001 From: Tunglies Date: Fri, 11 Apr 2025 17:27:56 +0800 Subject: [PATCH] Add AsyncHandler for wrapping task spawning --- src-tauri/src/config/config.rs | 3 +- src-tauri/src/core/handle.rs | 4 +- src-tauri/src/core/sysopt.rs | 3 +- src-tauri/src/core/tray/mod.rs | 59 ++++++++++++++------------ src-tauri/src/feat/clash.rs | 21 +++++---- src-tauri/src/feat/profile.rs | 3 +- src-tauri/src/feat/proxy.rs | 7 +-- src-tauri/src/lib.rs | 12 ++++-- src-tauri/src/process/async_handler.rs | 14 ++++++ src-tauri/src/process/mod.rs | 2 + src-tauri/src/utils/resolve.rs | 3 +- src-tauri/src/utils/server.rs | 3 +- 12 files changed, 82 insertions(+), 52 deletions(-) create mode 100644 src-tauri/src/process/async_handler.rs create mode 100644 src-tauri/src/process/mod.rs diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs index 6e32e59c..7cefb5d1 100644 --- a/src-tauri/src/config/config.rs +++ b/src-tauri/src/config/config.rs @@ -3,6 +3,7 @@ use crate::{ config::PrfItem, core::{handle, CoreManager}, enhance, logging, + process::AsyncHandler, utils::{dirs, help, logging::Type}, }; use anyhow::{anyhow, Result}; @@ -117,7 +118,7 @@ impl Config { // 在单独的任务中发送通知 if let Some((msg_type, msg_content)) = validation_result { - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(move || async move { sleep(Duration::from_secs(2)).await; handle::Handle::notice_message(msg_type, &msg_content); }); diff --git a/src-tauri/src/core/handle.rs b/src-tauri/src/core/handle.rs index f887c1a7..6140c1c3 100644 --- a/src-tauri/src/core/handle.rs +++ b/src-tauri/src/core/handle.rs @@ -3,7 +3,7 @@ use parking_lot::RwLock; use std::{sync::Arc, time::Duration}; use tauri::{AppHandle, Emitter, Manager, WebviewWindow}; -use crate::{logging, logging_error, utils::logging::Type}; +use crate::{logging, logging_error, process::AsyncHandler, utils::logging::Type}; /// 存储启动期间的错误消息 #[derive(Debug, Clone)] @@ -152,7 +152,7 @@ impl Handle { let window_clone = window.clone(); let errors_clone = errors.clone(); - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(move || async move { tokio::time::sleep(Duration::from_secs(2)).await; for error in errors_clone { diff --git a/src-tauri/src/core/sysopt.rs b/src-tauri/src/core/sysopt.rs index 7194c3b6..9f31a472 100644 --- a/src-tauri/src/core/sysopt.rs +++ b/src-tauri/src/core/sysopt.rs @@ -2,6 +2,7 @@ use crate::{ config::{Config, IVerge}, core::handle::Handle, logging, logging_error, + process::AsyncHandler, utils::logging::Type, }; use anyhow::Result; @@ -248,7 +249,7 @@ impl Sysopt { fn guard_proxy(&self) { let _lock = self.guard_state.lock(); - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(move || async move { // default duration is 10s let mut wait_secs = 10u64; diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index 5f18905e..d1afa6c5 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -7,6 +7,7 @@ use crate::{ config::Config, feat, module::{lightweight::entry_lightweight_mode, mihomo::Rate}, + process::AsyncHandler, resolve, utils::{dirs::find_target_icons, i18n::t, logging::Type, resolve::VERSION}, }; @@ -386,42 +387,46 @@ impl Tray { let speed_rate = Arc::clone(&self.speed_rate); let is_subscribed = Arc::clone(&self.is_subscribed); - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(move || { let mut shutdown = shutdown_rx; + let speed_rate = speed_rate.clone(); // 确保 Arc 被正确克隆 + let is_subscribed = is_subscribed.clone(); - 'outer: loop { - match Traffic::get_traffic_stream().await { - Ok(mut stream) => loop { - tokio::select! { - Some(traffic) = stream.next() => { - if let Ok(traffic) = traffic { - let guard = speed_rate.lock(); - let enable_tray_speed: bool = Config::verge().latest().enable_tray_speed.unwrap_or(true); - if !enable_tray_speed { - continue; - } - if let Some(sr) = guard.as_ref() { - if let Some(rate) = sr.update_and_check_changed(traffic.up, traffic.down) { - let _ = Tray::global().update_icon(Some(rate)); + Box::pin(async move { + 'outer: loop { + match Traffic::get_traffic_stream().await { + Ok(mut stream) => loop { + tokio::select! { + Some(traffic) = stream.next() => { + if let Ok(traffic) = traffic { + let guard = speed_rate.lock(); + let enable_tray_speed: bool = Config::verge() + .latest() + .enable_tray_speed + .unwrap_or(true); + if !enable_tray_speed { + continue; + } + if let Some(sr) = guard.as_ref() { + if let Some(rate) = sr.update_and_check_changed(traffic.up, traffic.down) { + let _ = Tray::global().update_icon(Some(rate)); + } } } } + _ = shutdown.recv() => break 'outer, + } + }, + Err(e) => { + log::error!(target: "app", "Failed to get traffic stream: {}", e); + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + if !*is_subscribed.read() { + break; } - _ = shutdown.recv() => break 'outer, - } - }, - Err(e) => { - log::error!(target: "app", "Failed to get traffic stream: {}", e); - // 如果获取流失败,等待一段时间后重试 - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - - // 检查是否应该继续重试 - if !*is_subscribed.read() { - break; } } } - } + }) }); Ok(()) diff --git a/src-tauri/src/feat/clash.rs b/src-tauri/src/feat/clash.rs index 5950806e..e58b2453 100644 --- a/src-tauri/src/feat/clash.rs +++ b/src-tauri/src/feat/clash.rs @@ -3,6 +3,7 @@ use crate::{ core::{handle, tray, CoreManager}, logging_error, module::mihomo::MihomoManager, + process::AsyncHandler, utils::{logging::Type, resolve}, }; use serde_yaml::{Mapping, Value}; @@ -10,7 +11,7 @@ use tauri::Manager; /// Restart the Clash core pub fn restart_clash_core() { - tauri::async_runtime::spawn(async { + AsyncHandler::spawn(move || async move { match CoreManager::global().restart_core().await { Ok(_) => { handle::Handle::refresh_clash(); @@ -26,19 +27,17 @@ pub fn restart_clash_core() { /// Restart the application pub fn restart_app() { - tauri::async_runtime::spawn_blocking(|| { - tauri::async_runtime::block_on(async { - logging_error!(Type::Core, true, CoreManager::global().stop_core().await); - resolve::resolve_reset_async().await; - let app_handle = handle::Handle::global().app_handle().unwrap(); - std::thread::sleep(std::time::Duration::from_secs(1)); - tauri::process::restart(&app_handle.env()); - }); + AsyncHandler::spawn(move || async move { + logging_error!(Type::Core, true, CoreManager::global().stop_core().await); + resolve::resolve_reset_async().await; + let app_handle = handle::Handle::global().app_handle().unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + tauri::process::restart(&app_handle.env()); }); } fn after_change_clash_mode() { - tauri::async_runtime::spawn(async { + AsyncHandler::spawn(move || async { match MihomoManager::global().get_connections().await { Ok(connections) => { if let Some(connections_array) = connections["connections"].as_array() { @@ -64,7 +63,7 @@ pub fn change_clash_mode(mode: String) { let json_value = serde_json::json!({ "mode": mode }); - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(move || async move { log::debug!(target: "app", "change clash mode to {mode}"); match MihomoManager::global().patch_configs(json_value).await { Ok(_) => { diff --git a/src-tauri/src/feat/profile.rs b/src-tauri/src/feat/profile.rs index ffe34c4d..f03e33fb 100644 --- a/src-tauri/src/feat/profile.rs +++ b/src-tauri/src/feat/profile.rs @@ -2,12 +2,13 @@ use crate::{ cmd, config::{Config, PrfItem, PrfOption}, core::{handle, CoreManager, *}, + process::AsyncHandler, }; use anyhow::{bail, Result}; /// Toggle proxy profile pub fn toggle_proxy_profile(profile_index: String) { - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(|| async move { let app_handle = handle::Handle::global().app_handle().unwrap(); match cmd::patch_profiles_config_by_profile_index(app_handle, profile_index).await { Ok(_) => { diff --git a/src-tauri/src/feat/proxy.rs b/src-tauri/src/feat/proxy.rs index d5afe0cb..5e24c3a0 100644 --- a/src-tauri/src/feat/proxy.rs +++ b/src-tauri/src/feat/proxy.rs @@ -1,6 +1,7 @@ use crate::{ config::{Config, IVerge}, core::handle, + process::AsyncHandler, }; use std::env; use tauri_plugin_clipboard_manager::ClipboardExt; @@ -10,7 +11,7 @@ pub fn toggle_system_proxy() { let enable = Config::verge().draft().enable_system_proxy; let enable = enable.unwrap_or(false); - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(move || async move { match super::patch_verge( IVerge { enable_system_proxy: Some(!enable), @@ -28,7 +29,7 @@ pub fn toggle_system_proxy() { /// Toggle TUN mode on/off pub fn toggle_tun_mode(not_save_file: Option) { - // tauri::async_runtime::spawn(async move { + // AsyncHandler::spawn(async { // logging!( // info, // Type::Service, @@ -44,7 +45,7 @@ pub fn toggle_tun_mode(not_save_file: Option) { let enable = Config::verge().data().enable_tun_mode; let enable = enable.unwrap_or(false); - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(async move || { match super::patch_verge( IVerge { enable_tun_mode: Some(!enable), diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 46e4e532..ee63e290 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -5,9 +5,11 @@ mod enhance; mod error; mod feat; mod module; +mod process; mod utils; use crate::{ core::hotkey, + process::AsyncHandler, utils::{resolve, resolve::resolve_scheme, server}, }; use config::Config; @@ -121,11 +123,13 @@ pub fn run() { use tauri_plugin_deep_link::DeepLinkExt; logging_error!(Type::System, true, app.deep_link().register_all()); } - app.deep_link().on_open_url(|event| { - tauri::async_runtime::spawn(async move { - if let Some(url) = event.urls().first() { - logging_error!(Type::Setup, true, resolve_scheme(url.to_string()).await); + AsyncHandler::spawn(move || { + let url = event.urls().first().map(|u| u.to_string()); + async move { + if let Some(url) = url { + logging_error!(Type::Setup, true, resolve_scheme(url).await); + } } }); }); diff --git a/src-tauri/src/process/async_handler.rs b/src-tauri/src/process/async_handler.rs new file mode 100644 index 00000000..c5a809d4 --- /dev/null +++ b/src-tauri/src/process/async_handler.rs @@ -0,0 +1,14 @@ +use std::future::Future; +use tauri::{async_runtime, async_runtime::JoinHandle}; + +pub struct AsyncHandler; + +impl AsyncHandler { + pub fn spawn(f: F) -> JoinHandle<()> + where + F: FnOnce() -> Fut + Send + 'static, + Fut: Future + Send + 'static, + { + async_runtime::spawn(f()) + } +} diff --git a/src-tauri/src/process/mod.rs b/src-tauri/src/process/mod.rs new file mode 100644 index 00000000..ac83ecc0 --- /dev/null +++ b/src-tauri/src/process/mod.rs @@ -0,0 +1,2 @@ +mod async_handler; +pub use async_handler::AsyncHandler; diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index 8f86f790..e46fd435 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -5,6 +5,7 @@ use crate::{ core::*, logging, logging_error, module::lightweight, + process::AsyncHandler, utils::{error, init, logging::Type, server}, wrap_err, }; @@ -211,7 +212,7 @@ pub fn create_window(is_showup: bool) { // 标记前端UI已准备就绪,向前端发送启动完成事件 let app_handle_clone = app_handle.clone(); - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(move || async move { use tauri::Emitter; logging!(info, Type::Window, true, "UI gets ready."); diff --git a/src-tauri/src/utils/server.rs b/src-tauri/src/utils/server.rs index 61870473..39d40c37 100644 --- a/src-tauri/src/utils/server.rs +++ b/src-tauri/src/utils/server.rs @@ -4,6 +4,7 @@ use super::resolve; use crate::{ config::{Config, IVerge, DEFAULT_PAC}, logging_error, + process::AsyncHandler, utils::logging::Type, }; use anyhow::{bail, Result}; @@ -47,7 +48,7 @@ pub async fn check_singleton() -> Result<()> { pub fn embed_server() { let port = IVerge::get_singleton_port(); - tauri::async_runtime::spawn(async move { + AsyncHandler::spawn(move || async move { let visible = warp::path!("commands" / "visible").map(move || { resolve::create_window(false); "ok"