diff --git a/UPDATELOG.md b/UPDATELOG.md index ff6499a0..3ec9828d 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -18,6 +18,9 @@ - 外部控制的开关 - 使用 socks 进行内核通信,以解决各种潜在的内核通信异常 +#### 重构了: + - Mihomo 内核不再使用 http 交互,而是使用 socket 进行通信 + ## v2.2.3 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index ab2b25f8..bd306bdd 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1824,6 +1824,12 @@ dependencies = [ "litrs", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "downcast-rs" version = "1.2.1" @@ -2913,7 +2919,7 @@ dependencies = [ "httpdate", "itoa 1.0.15", "pin-project-lite", - "socket2 0.5.8", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -2933,6 +2939,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "httparse", + "httpdate", "itoa 1.0.15", "pin-project-lite", "smallvec", @@ -2988,9 +2995,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" dependencies = [ "bytes", "futures-channel", @@ -2998,13 +3005,29 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "hyper 1.6.0", + "libc", "pin-project-lite", - "socket2 0.5.8", + "socket2 0.5.9", "tokio", "tower-service", "tracing", ] +[[package]] +name = "hyperlocal" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" +dependencies = [ + "hex", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "iana-time-zone" version = "0.1.62" @@ -3852,10 +3875,18 @@ dependencies = [ name = "mihomo_api" version = "0.0.0" dependencies = [ - "reqwest", - "serde", + "async-trait", + "dotenv", + "futures", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "hyperlocal", + "lazy_static", "serde_json", + "time", "tokio", + "tokio-util", ] [[package]] @@ -5344,7 +5375,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.5.8", + "socket2 0.5.9", "thiserror 2.0.12", "tokio", "tracing", @@ -5380,7 +5411,7 @@ dependencies = [ "cfg_aliases 0.2.1", "libc", "once_cell", - "socket2 0.5.8", + "socket2 0.5.9", "tracing", "windows-sys 0.59.0", ] @@ -6484,9 +6515,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", @@ -7484,7 +7515,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.8", + "socket2 0.5.9", "tokio-macros", "tracing", "windows-sys 0.52.0", diff --git a/src-tauri/src/cmd/clash.rs b/src-tauri/src/cmd/clash.rs index e07f84e9..b9c37b74 100644 --- a/src-tauri/src/cmd/clash.rs +++ b/src-tauri/src/cmd/clash.rs @@ -2,6 +2,7 @@ use super::CmdResult; use crate::{ config::*, core::*, feat, module::mihomo::MihomoManager, process::AsyncHandler, wrap_err, }; +use mihomo_api::model::MihomoClient; use serde_yaml::Mapping; /// 复制Clash环境变量 @@ -70,6 +71,7 @@ pub async fn clash_api_get_proxy_delay( MihomoManager::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 cee4c68b..1567c6d9 100644 --- a/src-tauri/src/cmd/proxy.rs +++ b/src-tauri/src/cmd/proxy.rs @@ -1,24 +1,23 @@ +use mihomo_api::model::MihomoClient; + use super::CmdResult; use crate::module::mihomo::MihomoManager; #[tauri::command] pub async fn get_proxies() -> CmdResult { - let mannager = MihomoManager::global(); - - mannager - .refresh_proxies() - .await - .map(|_| mannager.get_proxies()) - .or_else(|_| Ok(mannager.get_proxies())) + let manager = MihomoManager::global(); + manager.refresh_proxies().await.map_err(|e| e.to_string())?; + let data = manager.get_data_proxies().await; + Ok(data) } #[tauri::command] pub async fn get_providers_proxies() -> CmdResult { - let mannager = MihomoManager::global(); - - mannager + let manager = MihomoManager::global(); + manager .refresh_providers_proxies() .await - .map(|_| mannager.get_providers_proxies()) - .or_else(|_| Ok(mannager.get_providers_proxies())) + .map_err(|e| e.to_string())?; + let data = manager.get_data_providers_proxies().await; + Ok(data) } diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs index 26764c01..e2936b96 100644 --- a/src-tauri/src/config/clash.rs +++ b/src-tauri/src/config/clash.rs @@ -51,6 +51,10 @@ impl IClashTemp { map.insert("ipv6".into(), true.into()); map.insert("mode".into(), "rule".into()); map.insert("external-controller".into(), "127.0.0.1:9097".into()); + #[cfg(not(target_os = "windows"))] + map.insert("external-controller-unix".into(), "mihomo.sock".into()); + #[cfg(target_os = "windows")] + map.insert("external-controller-pipe".into(), r"\\.\pipe\mihomo".into()); let mut cors_map = Mapping::new(); cors_map.insert("allow-private-network".into(), true.into()); cors_map.insert("allow-origins".into(), vec!["*"].into()); diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index 2ab0982b..4840879b 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -15,6 +15,7 @@ use crate::{ }, }; use anyhow::Result; +use mihomo_api::model::MihomoClient; use once_cell::sync::OnceCell; use std::{fmt, path::PathBuf, sync::Arc}; use tauri_plugin_shell::{process::CommandChild, ShellExt}; diff --git a/src-tauri/src/feat/clash.rs b/src-tauri/src/feat/clash.rs index e58b2453..da446116 100644 --- a/src-tauri/src/feat/clash.rs +++ b/src-tauri/src/feat/clash.rs @@ -6,6 +6,7 @@ use crate::{ process::AsyncHandler, utils::{logging::Type, resolve}, }; +use mihomo_api::model::MihomoClient; use serde_yaml::{Mapping, Value}; use tauri::Manager; diff --git a/src-tauri/src/feat/window.rs b/src-tauri/src/feat/window.rs index 7bc986ad..998cbb02 100644 --- a/src-tauri/src/feat/window.rs +++ b/src-tauri/src/feat/window.rs @@ -1,3 +1,5 @@ +use mihomo_api::model::MihomoClient; + #[cfg(target_os = "macos")] use crate::AppHandleManager; use crate::{ @@ -74,12 +76,11 @@ pub fn quit() { "enable": false } }); - timeout( - Duration::from_secs(1), - MihomoManager::global().patch_configs(disable_tun), - ) - .await - .is_ok() + + let patch_future = + async { MihomoManager::global().patch_configs(disable_tun).await }; + + timeout(Duration::from_secs(1), patch_future).await.is_ok() } else { true }; diff --git a/src-tauri/src/module/mihomo.rs b/src-tauri/src/module/mihomo.rs index 47929b92..f7e9060c 100644 --- a/src-tauri/src/module/mihomo.rs +++ b/src-tauri/src/module/mihomo.rs @@ -1,4 +1,4 @@ -use crate::config::Config; +use crate::{config::Config, utils::dirs::app_socket_path}; use mihomo_api; use once_cell::sync::{Lazy, OnceCell}; use std::sync::Mutex; @@ -24,20 +24,18 @@ impl MihomoManager { &INSTANCE } - pub fn global() -> mihomo_api::MihomoManager { + pub fn global() -> &'static mihomo_api::MihomoManager { let instance = MihomoManager::__global(); - let (current_server, headers) = MihomoManager::get_clash_client_info().unwrap(); - let lock = instance.mihomo.lock().unwrap(); - if let Some(mihomo) = lock.get() { - if mihomo.get_mihomo_server() == current_server { - return mihomo.clone(); - } + let mihomo = &instance.mihomo; + let lock = mihomo.lock().unwrap(); + + if lock.get().is_none() { + let socket_path = MihomoManager::get_socket_path(); + lock.set(mihomo_api::MihomoManager::new(socket_path)).ok(); } - lock.set(mihomo_api::MihomoManager::new(current_server, headers)) - .ok(); - lock.get().unwrap().clone() + unsafe { std::mem::transmute(lock.get().unwrap()) } } } @@ -67,4 +65,12 @@ impl MihomoManager { let token = http::header::HeaderValue::from_str(&auth).unwrap(); (ws_url, token) } + + fn get_socket_path() -> String { + #[cfg(unix)] + let socket_path = app_socket_path().unwrap(); + #[cfg(windows)] + let socket_path = r"\\.\pipe\mihomo"; + socket_path + } } diff --git a/src-tauri/src/utils/dirs.rs b/src-tauri/src/utils/dirs.rs index ec54b37c..b5c350d8 100644 --- a/src-tauri/src/utils/dirs.rs +++ b/src-tauri/src/utils/dirs.rs @@ -179,3 +179,10 @@ pub fn get_encryption_key() -> Result> { Ok(key) } } + +pub fn app_socket_path() -> Result { + let app_dir = app_home_dir()?; + let socket_path = app_dir.join("mihomo.sock"); + let socket_path = path_to_str(&socket_path)?; + Ok(socket_path.to_string()) +} diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index 09bafbd9..379e03cf 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -15,8 +15,7 @@ use parking_lot::RwLock; use percent_encoding::percent_decode_str; use serde_json; use serde_yaml::Mapping; -use std::net::TcpListener; -use std::sync::Arc; +use std::{net::TcpListener, sync::Arc}; use tauri::{App, Manager}; use tauri::Url; diff --git a/src-tauri/src_crates/crate_mihomo_api/scripts/test_windows.ps1 b/src-tauri/src_crates/crate_mihomo_api/scripts/test_windows.ps1 deleted file mode 100644 index d4b5e62e..00000000 --- a/src-tauri/src_crates/crate_mihomo_api/scripts/test_windows.ps1 +++ /dev/null @@ -1,13 +0,0 @@ -$pipeName = "\\.\pipe\mihomo" -$pipe = new-object System.IO.Pipes.NamedPipeClientStream(".", "mihomo", [System.IO.Pipes.PipeDirection]::InOut) -$pipe.Connect(1000) # 尝试连接 1 秒 -if ($pipe.IsConnected) { - Write-Host "成功连接到管道" - # 示例写入或读取可以加上如下内容 - # $writer = new-object System.IO.StreamWriter($pipe) - # $writer.WriteLine("hello pipe") - # $writer.Flush() - $pipe.Close() -} else { - Write-Host "连接失败" -} diff --git a/src-tauri/src_crates/crate_mihomo_api/src/lib.rs b/src-tauri/src_crates/crate_mihomo_api/src/lib.rs index db3c769a..89a23b01 100644 --- a/src-tauri/src_crates/crate_mihomo_api/src/lib.rs +++ b/src-tauri/src_crates/crate_mihomo_api/src/lib.rs @@ -42,8 +42,7 @@ // } pub mod model; -pub use model::E; -pub use model::MihomoData; -pub use model::MihomoManager; +pub use model::{E, MihomoData, MihomoManager}; +pub mod platform; pub mod sock; -pub mod platform; \ No newline at end of file +pub use platform::Client; diff --git a/src-tauri/src_crates/crate_mihomo_api/src/model.rs b/src-tauri/src_crates/crate_mihomo_api/src/model.rs index 1e96594e..4ba81c07 100644 --- a/src-tauri/src_crates/crate_mihomo_api/src/model.rs +++ b/src-tauri/src_crates/crate_mihomo_api/src/model.rs @@ -40,7 +40,7 @@ pub trait MihomoClient: Sized { async fn refresh_proxies(&self) -> Result<&Self, E>; async fn refresh_providers_proxies(&self) -> Result<&Self, E>; async fn get_connections(&self) -> Result; - async fn delete_connections(&self, id: &str) -> Result<(), E>; + async fn delete_connection(&self, id: &str) -> Result<(), E>; async fn test_proxy_delay( &self, name: &str, diff --git a/src-tauri/src_crates/crate_mihomo_api/src/sock.rs b/src-tauri/src_crates/crate_mihomo_api/src/sock.rs index 593c50c6..89011dd7 100644 --- a/src-tauri/src_crates/crate_mihomo_api/src/sock.rs +++ b/src-tauri/src_crates/crate_mihomo_api/src/sock.rs @@ -1,10 +1,9 @@ -use crate::model::E; +use crate::{model::E, platform::Client}; use async_trait::async_trait; use hyper::Method; use serde_json::Value; use std::sync::Arc; use tokio::sync::Mutex; -use crate::platform::Client; use crate::{ MihomoData, @@ -47,7 +46,9 @@ impl MihomoClient for MihomoManager { body: Option, ) -> Result { let client = self.client.lock().await; - client.send_request(self.socket_path.clone(), path, method, body).await + client + .send_request(self.socket_path.clone(), path, method, body) + .await } async fn get_version(&self) -> Result { @@ -96,7 +97,7 @@ impl MihomoClient for MihomoManager { Ok(data) } - async fn delete_connections(&self, id: &str) -> Result<(), E> { + async fn delete_connection(&self, id: &str) -> Result<(), E> { let _ = self .send_request(&format!("/connections/{}", id), Method::DELETE, None) .await?;