From 10f467a8b3046fa0aa0fc6812aaf61eab0d453e2 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Wed, 25 Jun 2025 01:32:50 +0800 Subject: [PATCH] refactor: replace MihomoManager with IpcManager and remove Mihomo module --- src-tauri/Cargo.toml | 2 +- src-tauri/src/cmd/clash.rs | 7 +- src-tauri/src/cmd/proxy.rs | 106 +++++++++++++++++++++++-------- src-tauri/src/core/core.rs | 7 +- src-tauri/src/core/tray/mod.rs | 4 +- src-tauri/src/feat/clash.rs | 8 +-- src-tauri/src/feat/proxy.rs | 8 +-- src-tauri/src/feat/window.rs | 4 +- src-tauri/src/ipc/general.rs | 64 ++++++++++++++----- src-tauri/src/ipc/mod.rs | 5 ++ src-tauri/src/module/mihomo.rs | 113 --------------------------------- src-tauri/src/module/mod.rs | 1 - src-tauri/src/utils/dirs.rs | 6 +- 13 files changed, 154 insertions(+), 181 deletions(-) delete mode 100644 src-tauri/src/module/mihomo.rs diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 57957e60..a71e441b 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -78,7 +78,7 @@ hmac = "0.12.1" sha2 = "0.10.9" hex = "0.4.3" scopeguard = "1.2.0" -kode-bridge = "0.1.0" +kode-bridge = "0.1.2" [target.'cfg(windows)'.dependencies] runas = "=1.2.0" diff --git a/src-tauri/src/cmd/clash.rs b/src-tauri/src/cmd/clash.rs index 02b9ad96..470ac3c9 100644 --- a/src-tauri/src/cmd/clash.rs +++ b/src-tauri/src/cmd/clash.rs @@ -1,7 +1,5 @@ use super::CmdResult; -use crate::{ - config::*, core::*, feat, module::mihomo::MihomoManager, process::AsyncHandler, wrap_err, -}; +use crate::{config::*, core::*, feat, ipc::IpcManager, process::AsyncHandler, wrap_err}; use serde_yaml::Mapping; /// 复制Clash环境变量 @@ -90,9 +88,10 @@ pub async fn clash_api_get_proxy_delay( url: Option, timeout: i32, ) -> CmdResult { - MihomoManager::global() + IpcManager::global() .test_proxy_delay(&name, url, timeout) .await + .map_err(|e| e.to_string()) } /// 测试URL延迟 diff --git a/src-tauri/src/cmd/proxy.rs b/src-tauri/src/cmd/proxy.rs index 1ba6eec4..6034f218 100644 --- a/src-tauri/src/cmd/proxy.rs +++ b/src-tauri/src/cmd/proxy.rs @@ -1,8 +1,10 @@ use super::CmdResult; -use crate::module::mihomo::MihomoManager; -use std::time::Duration; - -use crate::state::proxy::ProxyRequestCache; +use crate::{core::handle, module::mihomo::MihomoManager, state::proxy::CmdProxyState}; +use std::{ + sync::Mutex, + time::{Duration, Instant}, +}; +use tauri::Manager; const PROXIES_REFRESH_INTERVAL: Duration = Duration::from_secs(60); const PROVIDERS_REFRESH_INTERVAL: Duration = Duration::from_secs(60); @@ -10,34 +12,88 @@ const PROVIDERS_REFRESH_INTERVAL: Duration = Duration::from_secs(60); #[tauri::command] pub async fn get_proxies() -> CmdResult { let manager = MihomoManager::global(); - let cache = ProxyRequestCache::global(); - let key = ProxyRequestCache::make_key("proxies", "default"); - let value = cache - .get_or_fetch(key, PROXIES_REFRESH_INTERVAL, || async { - manager.get_refresh_proxies().await.expect("fetch failed") - }) - .await; - Ok((*value).clone()) + + let app_handle = handle::Handle::global().app_handle().unwrap(); + let cmd_proxy_state = app_handle.state::>(); + + let should_refresh = { + let mut state = cmd_proxy_state.lock().unwrap(); + let now = Instant::now(); + if now.duration_since(state.last_refresh_time) > PROXIES_REFRESH_INTERVAL { + state.need_refresh = true; + state.last_refresh_time = now; + } + state.need_refresh + }; + + if should_refresh { + let proxies = manager.get_refresh_proxies().await?; + { + let mut state = cmd_proxy_state.lock().unwrap(); + state.proxies = Box::new(proxies); + state.need_refresh = false; + } + log::debug!(target: "app", "proxies刷新成功"); + } + + let proxies = { + let state = cmd_proxy_state.lock().unwrap(); + state.proxies.clone() + }; + Ok(*proxies) } /// 强制刷新代理缓存用于profile切换 #[tauri::command] pub async fn force_refresh_proxies() -> CmdResult { - let cache = ProxyRequestCache::global(); - let key = ProxyRequestCache::make_key("proxies", "default"); - cache.map.remove(&key); - get_proxies().await + let manager = MihomoManager::global(); + let app_handle = handle::Handle::global().app_handle().unwrap(); + let cmd_proxy_state = app_handle.state::>(); + + log::debug!(target: "app", "强制刷新代理缓存"); + + let proxies = manager.get_refresh_proxies().await?; + + { + let mut state = cmd_proxy_state.lock().unwrap(); + state.proxies = Box::new(proxies.clone()); + state.need_refresh = false; + state.last_refresh_time = Instant::now(); + } + + log::debug!(target: "app", "强制刷新代理缓存完成"); + Ok(proxies) } #[tauri::command] pub async fn get_providers_proxies() -> CmdResult { - let manager = MihomoManager::global(); - let cache = ProxyRequestCache::global(); - let key = ProxyRequestCache::make_key("providers", "default"); - let value = cache - .get_or_fetch(key, PROVIDERS_REFRESH_INTERVAL, || async { - manager.get_providers_proxies().await.expect("fetch failed") - }) - .await; - Ok((*value).clone()) + let app_handle = handle::Handle::global().app_handle().unwrap(); + let cmd_proxy_state = app_handle.state::>(); + + let should_refresh = { + let mut state = cmd_proxy_state.lock().unwrap(); + let now = Instant::now(); + if now.duration_since(state.last_refresh_time) > PROVIDERS_REFRESH_INTERVAL { + state.need_refresh = true; + state.last_refresh_time = now; + } + state.need_refresh + }; + + if should_refresh { + let manager = MihomoManager::global(); + let providers = manager.get_providers_proxies().await?; + { + let mut state = cmd_proxy_state.lock().unwrap(); + state.providers_proxies = Box::new(providers); + state.need_refresh = false; + } + log::debug!(target: "app", "providers_proxies刷新成功"); + } + + let providers_proxies = { + let state = cmd_proxy_state.lock().unwrap(); + state.providers_proxies.clone() + }; + Ok(*providers_proxies) } diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index fe1481ae..be5f2c49 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -4,8 +4,8 @@ use crate::{ handle, service::{self}, }, + ipc::IpcManager, logging, logging_error, - module::mihomo::MihomoManager, utils::{ dirs, help::{self}, @@ -413,10 +413,7 @@ impl CoreManager { logging_error!(Type::Core, true, "{}", msg); msg }); - match MihomoManager::global() - .put_configs_force(run_path_str?) - .await - { + match IpcManager::global().put_configs_force(run_path_str?).await { Ok(_) => { Config::runtime().apply(); logging!(info, Type::Core, true, "Configuration updated successfully"); diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index a2b822d8..21cc20cd 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -2,11 +2,13 @@ use once_cell::sync::OnceCell; use tauri::tray::TrayIconBuilder; #[cfg(target_os = "macos")] pub mod speed_rate; +#[cfg(target_os = "macos")] +use crate::ipc::Rate; use crate::{ cmd, config::Config, feat, logging, - module::{lightweight::is_in_lightweight_mode, mihomo::Rate}, + module::lightweight::is_in_lightweight_mode, utils::{dirs::find_target_icons, i18n::t, resolve::VERSION}, Type, }; diff --git a/src-tauri/src/feat/clash.rs b/src-tauri/src/feat/clash.rs index 3afab1f3..33c1fb15 100644 --- a/src-tauri/src/feat/clash.rs +++ b/src-tauri/src/feat/clash.rs @@ -1,8 +1,8 @@ use crate::{ config::Config, core::{handle, tray, CoreManager}, + ipc::IpcManager, logging_error, - module::mihomo::MihomoManager, process::AsyncHandler, utils::{logging::Type, resolve}, }; @@ -38,12 +38,12 @@ pub fn restart_app() { fn after_change_clash_mode() { AsyncHandler::spawn(move || async { - match MihomoManager::global().get_connections().await { + 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 _ = MihomoManager::global().delete_connection(id).await; + let _ = IpcManager::global().delete_connection(id).await; } } } @@ -65,7 +65,7 @@ pub fn change_clash_mode(mode: String) { }); AsyncHandler::spawn(move || async move { log::debug!(target: "app", "change clash mode to {mode}"); - match MihomoManager::global().patch_configs(json_value).await { + match IpcManager::global().patch_configs(json_value).await { Ok(_) => { // 更新订阅 Config::clash().data_mut().patch_config(mapping); diff --git a/src-tauri/src/feat/proxy.rs b/src-tauri/src/feat/proxy.rs index 1568d505..4ce3fd5a 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, + ipc::IpcManager, process::AsyncHandler, }; use std::env; @@ -18,11 +19,8 @@ pub fn toggle_system_proxy() { AsyncHandler::spawn(move || async move { // 如果当前系统代理即将关闭,且自动关闭连接设置为true,则关闭所有连接 if enable && auto_close_connection { - if let Err(err) = crate::module::mihomo::MihomoManager::global() - .close_all_connections() - .await - { - log::error!(target: "app", "Failed to close all connections: {err}"); + if let Err(err) = IpcManager::global().close_all_connections().await { + log::error!(target: "app", "Failed to close all connections: {}", err); } } diff --git a/src-tauri/src/feat/window.rs b/src-tauri/src/feat/window.rs index 40dfb435..d301eb7c 100644 --- a/src-tauri/src/feat/window.rs +++ b/src-tauri/src/feat/window.rs @@ -3,8 +3,8 @@ use crate::AppHandleManager; use crate::{ config::Config, core::{handle, sysopt, CoreManager}, + ipc::IpcManager, logging, - module::mihomo::MihomoManager, utils::logging::Type, }; @@ -107,7 +107,7 @@ async fn clean_async() -> bool { }); match timeout( Duration::from_secs(2), - MihomoManager::global().patch_configs(disable_tun), + IpcManager::global().patch_configs(disable_tun), ) .await { diff --git a/src-tauri/src/ipc/general.rs b/src-tauri/src/ipc/general.rs index c00d165b..72a05296 100644 --- a/src-tauri/src/ipc/general.rs +++ b/src-tauri/src/ipc/general.rs @@ -1,15 +1,45 @@ -use kode_bridge::{errors::AnyError, IpcHttpClient}; +use kode_bridge::{ + errors::{AnyError, AnyResult}, + types::Response, + IpcHttpClient, +}; use serde_json::json; +use std::sync::OnceLock; + +use crate::utils::dirs::ipc_path; pub struct IpcManager { - client: IpcHttpClient, + ipc_path: String, +} + +static INSTANCE: OnceLock = OnceLock::new(); + +impl IpcManager { + pub fn global() -> &'static IpcManager { + INSTANCE.get_or_init(|| { + let ipc_path_buf = ipc_path().unwrap(); + let ipc_path = ipc_path_buf.to_str().unwrap_or_default(); + let instance = IpcManager { + ipc_path: ipc_path.to_string(), + }; + println!( + "IpcManager initialized with IPC path: {}", + instance.ipc_path + ); + instance + }) + } } impl IpcManager { - pub async fn new(socket_path: &str) -> Self { - IpcManager { - client: IpcHttpClient::new(socket_path).await, - } + pub async fn request( + &self, + method: &str, + path: &str, + body: Option<&serde_json::Value>, + ) -> AnyResult { + let client = IpcHttpClient::new(&self.ipc_path); + Ok(client.request(method, path, body).await?) } } @@ -20,18 +50,18 @@ impl IpcManager { path: &str, body: Option<&serde_json::Value>, ) -> Result { - // Ok(self.client.request(method, path, body).await?.json()?) - let response = self.client.request(method, path, body).await?; - if method == "PATCH" { - if response.status == 204 { - Ok(serde_json::json!({"code": 204})) - } else { - Ok(response.json()?) + let response = IpcManager::global().request(method, path, body).await?; + match method { + "GET" => Ok(response.json()?), + "PATCH" => { + if response.status == 204 { + Ok(serde_json::json!({"code": 204})) + } else { + Ok(response.json()?) + } } - } else if method == "PUT" { - Ok(json!(response.body)) - } else { - Ok(response.json()?) + "PUT" => Ok(json!(response.body)), + _ => Ok(response.json()?), } } diff --git a/src-tauri/src/ipc/mod.rs b/src-tauri/src/ipc/mod.rs index 6fb21e98..bda6b301 100644 --- a/src-tauri/src/ipc/mod.rs +++ b/src-tauri/src/ipc/mod.rs @@ -1,3 +1,8 @@ pub mod general; pub use general::IpcManager; + +pub struct Rate { + // pub up: usize, + // pub down: usize, +} diff --git a/src-tauri/src/module/mihomo.rs b/src-tauri/src/module/mihomo.rs deleted file mode 100644 index 5a98743e..00000000 --- a/src-tauri/src/module/mihomo.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::config::Config; -use crate::ipc::IpcManager; -#[cfg(unix)] -use crate::utils::dirs::{ipc_path, path_to_str}; -use once_cell::sync::Lazy; -use parking_lot::{Mutex, RwLock}; -use std::time::{Duration, Instant}; -use tauri::http::HeaderMap; - -// 缓存的最大有效期(5秒) -const CACHE_TTL: Duration = Duration::from_secs(5); - -#[derive(Debug, Clone, Default, PartialEq)] -pub struct Rate { - pub up: u64, - pub down: u64, -} -// 缓存MihomoManager实例 -struct MihomoCache { - manager: IpcManager, - created_at: Instant, - server: String, -} -// 使用RwLock替代Mutex,允许多个读取操作并发进行 -pub struct MihomoManager { - mihomo_cache: RwLock>, - create_lock: Mutex<()>, -} - -impl MihomoManager { - fn __global() -> &'static MihomoManager { - static INSTANCE: Lazy = Lazy::new(|| MihomoManager { - mihomo_cache: RwLock::new(None), - create_lock: Mutex::new(()), - }); - &INSTANCE - } - - pub fn global() -> IpcManager { - let instance = MihomoManager::__global(); - - // 尝试从缓存读取(只需读锁) - { - let cache = instance.mihomo_cache.read(); - if let Some(cache_entry) = &*cache { - let (current_server, _) = MihomoManager::get_clash_client_info() - .unwrap_or_else(|| (String::new(), HeaderMap::new())); - - // 检查缓存是否有效 - if cache_entry.server == current_server - && cache_entry.created_at.elapsed() < CACHE_TTL - { - return cache_entry.manager.clone(); - } - } - } - - // 缓存无效,获取创建锁 - let _create_guard = instance.create_lock.lock(); - - // 再次检查缓存(双重检查锁定模式) - { - let cache = instance.mihomo_cache.read(); - if let Some(cache_entry) = &*cache { - let (current_server, _) = MihomoManager::get_clash_client_info() - .unwrap_or_else(|| (String::new(), HeaderMap::new())); - - if cache_entry.server == current_server - && cache_entry.created_at.elapsed() < CACHE_TTL - { - return cache_entry.manager; - } - } - } - - // 创建新实例 - let (current_server, headers) = MihomoManager::get_clash_client_info() - .unwrap_or_else(|| (String::new(), HeaderMap::new())); - // ! unix - #[cfg(unix)] - let manager = IpcManager::new(path_to_str(ipc_path()?)); - // ! windows - - // 更新缓存 - { - let mut cache = instance.mihomo_cache.write(); - *cache = Some(MihomoCache { - manager: manager, - created_at: Instant::now(), - server: current_server, - }); - } - - manager - } -} - -impl MihomoManager { - pub fn get_clash_client_info() -> Option<(String, HeaderMap)> { - let client = { Config::clash().latest_ref().get_client_info() }; - let server = format!("http://{}", client.server); - let mut headers = HeaderMap::new(); - headers.insert("Content-Type", "application/json".parse().unwrap()); - if let Some(secret) = client.secret { - let secret = format!("Bearer {secret}").parse().unwrap(); - headers.insert("Authorization", secret); - } - - Some((server, headers)) - } - - // 已移除未使用的 get_clash_client_info_or_default 和 get_traffic_ws_url 方法 -} diff --git a/src-tauri/src/module/mod.rs b/src-tauri/src/module/mod.rs index 39cb3c83..64373b9d 100644 --- a/src-tauri/src/module/mod.rs +++ b/src-tauri/src/module/mod.rs @@ -1,3 +1,2 @@ pub mod lightweight; -pub mod mihomo; pub mod sysinfo; diff --git a/src-tauri/src/utils/dirs.rs b/src-tauri/src/utils/dirs.rs index bafdc67d..372b2c4f 100644 --- a/src-tauri/src/utils/dirs.rs +++ b/src-tauri/src/utils/dirs.rs @@ -245,18 +245,18 @@ pub fn get_encryption_key() -> Result> { #[cfg(target_os = "macos")] pub fn ipc_path() -> Result { - let res_dir = app_resources_dir()?; + let res_dir = app_home_dir()?; Ok(res_dir.join("mihomo.sock")) } #[cfg(target_os = "linux")] pub fn ipc_path() -> Result { - let res_dir = app_resources_dir()?; + let res_dir = app_home_dir()?; Ok(res_dir.join("mihomo.sock")) } #[cfg(target_os = "windows")] pub fn ipc_path() -> Result { - let res_dir = app_resources_dir()?; + let res_dir = app_home_dir()?; Ok(res_dir.join(r"\\.\pipe\mihomo")) }