Refactor Mihomo API integration and remove crate_mihomo_api
- Removed the `mihomo_api` crate and its dependencies from the project. - Introduced `IpcManager` for handling IPC communication with Mihomo. - Implemented IPC methods for managing proxies, connections, and configurations. - Updated `MihomoManager` to utilize `IpcManager` instead of the removed crate. - Added platform-specific IPC socket path handling for macOS, Linux, and Windows. - Cleaned up related tests and configuration files.
This commit is contained in:
496
src-tauri/Cargo.lock
generated
496
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -70,15 +70,15 @@ getrandom = "0.3.3"
|
||||
futures = "0.3.31"
|
||||
sys-locale = "0.3.2"
|
||||
async-trait = "0.1.88"
|
||||
mihomo_api = { path = "src_crates/crate_mihomo_api" }
|
||||
ab_glyph = "0.2.29"
|
||||
tungstenite = "0.27.0"
|
||||
libc = "0.2.174"
|
||||
gethostname = "1.0.2"
|
||||
hmac = "0.12.1"
|
||||
sha2 = "0.10.9"
|
||||
hex = "0.4.3"
|
||||
scopeguard = "1.2.0"
|
||||
tauri-plugin-notification = "2.3.0"
|
||||
dashmap = "7.0.0-rc2"
|
||||
kode-bridge = "0.1.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.2.0"
|
||||
@@ -142,9 +142,7 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
criterion = "0.6.0"
|
||||
tempfile = "3.20.0"
|
||||
|
||||
[workspace]
|
||||
members = ["src_crates/crate_mihomo_api"]
|
||||
|
||||
[[bench]]
|
||||
name = "draft_benchmark"
|
||||
harness = false
|
||||
# [patch.crates-io]
|
||||
# bitflags = { git = "https://github.com/bitflags/bitflags", rev = "2.9.0" }
|
||||
# zerocopy = { git = "https://github.com/google/zerocopy", rev = "v0.8.24" }
|
||||
# tungstenite = { git = "https://github.com/snapview/tungstenite-rs", rev = "v0.26.2" }
|
||||
|
||||
130
src-tauri/src/ipc/general.rs
Normal file
130
src-tauri/src/ipc/general.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
use kode_bridge::{errors::AnyError, IpcHttpClient};
|
||||
use serde_json::json;
|
||||
|
||||
pub struct IpcManager {
|
||||
client: IpcHttpClient,
|
||||
}
|
||||
|
||||
impl IpcManager {
|
||||
pub async fn new(socket_path: &str) -> Self {
|
||||
IpcManager {
|
||||
client: IpcHttpClient::new(socket_path).await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IpcManager {
|
||||
pub async fn send_request(
|
||||
&self,
|
||||
method: &str,
|
||||
path: &str,
|
||||
body: Option<&serde_json::Value>,
|
||||
) -> Result<serde_json::Value, AnyError> {
|
||||
// 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()?)
|
||||
}
|
||||
} else if method == "PUT" {
|
||||
Ok(json!(response.body))
|
||||
} else {
|
||||
Ok(response.json()?)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_refresh_proxies(&self) -> Result<serde_json::Value, AnyError> {
|
||||
let url = "/proxies";
|
||||
self.send_request("GET", url, None).await
|
||||
}
|
||||
pub async fn get_providers_proxies(&self) -> Result<serde_json::Value, AnyError> {
|
||||
let url = "/providers/proxies";
|
||||
self.send_request("GET", url, None).await
|
||||
}
|
||||
|
||||
pub async fn close_all_connections(&self) -> Result<(), AnyError> {
|
||||
let url = "/connections";
|
||||
let response = self.send_request("DELETE", url, None).await?;
|
||||
if response["code"] == 204 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(AnyError::from(
|
||||
response["message"]
|
||||
.as_str()
|
||||
.unwrap_or("unknown error")
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IpcManager {
|
||||
pub async fn is_mihomo_running(&self) -> Result<(), AnyError> {
|
||||
let url = "/version";
|
||||
let _response = self.send_request("GET", url, None).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn put_configs_force(&self, clash_config_path: &str) -> Result<(), AnyError> {
|
||||
let url = "/configs?force=true";
|
||||
let payload = serde_json::json!({
|
||||
"path": clash_config_path,
|
||||
});
|
||||
let _response = self.send_request("PUT", url, Some(&payload)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn patch_configs(&self, config: serde_json::Value) -> Result<(), AnyError> {
|
||||
let url = "/configs";
|
||||
let response = self.send_request("PATCH", url, Some(&config)).await?;
|
||||
if response["code"] == 204 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(AnyError::from(
|
||||
response["message"]
|
||||
.as_str()
|
||||
.unwrap_or("unknown error")
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn test_proxy_delay(
|
||||
&self,
|
||||
name: &str,
|
||||
test_url: Option<String>,
|
||||
timeout: i32,
|
||||
) -> Result<serde_json::Value, AnyError> {
|
||||
let test_url =
|
||||
test_url.unwrap_or_else(|| "https://cp.cloudflare.com/generate_204".to_string());
|
||||
let url = format!(
|
||||
"/proxies/{}/delay?url={}&timeout={}",
|
||||
name, test_url, timeout
|
||||
);
|
||||
let response = self.send_request("GET", &url, None).await?;
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn get_connections(&self) -> Result<serde_json::Value, AnyError> {
|
||||
let url = "/connections";
|
||||
let response = self.send_request("GET", url, None).await?;
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn delete_connection(&self, id: &str) -> Result<(), AnyError> {
|
||||
let url = format!("/connections/{}", id);
|
||||
let response = self.send_request("DELETE", &url, None).await?;
|
||||
if response["code"] == 204 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(AnyError::from(
|
||||
response["message"]
|
||||
.as_str()
|
||||
.unwrap_or("unknown error")
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
3
src-tauri/src/ipc/mod.rs
Normal file
3
src-tauri/src/ipc/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod general;
|
||||
|
||||
pub use general::IpcManager;
|
||||
@@ -3,6 +3,7 @@ pub mod config;
|
||||
mod core;
|
||||
mod enhance;
|
||||
mod feat;
|
||||
mod ipc;
|
||||
mod module;
|
||||
mod process;
|
||||
mod state;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::config::Config;
|
||||
use mihomo_api;
|
||||
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};
|
||||
@@ -15,7 +17,7 @@ pub struct Rate {
|
||||
}
|
||||
// 缓存MihomoManager实例
|
||||
struct MihomoCache {
|
||||
manager: mihomo_api::MihomoManager,
|
||||
manager: IpcManager,
|
||||
created_at: Instant,
|
||||
server: String,
|
||||
}
|
||||
@@ -34,7 +36,7 @@ impl MihomoManager {
|
||||
&INSTANCE
|
||||
}
|
||||
|
||||
pub fn global() -> mihomo_api::MihomoManager {
|
||||
pub fn global() -> IpcManager {
|
||||
let instance = MihomoManager::__global();
|
||||
|
||||
// 尝试从缓存读取(只需读锁)
|
||||
@@ -66,7 +68,7 @@ impl MihomoManager {
|
||||
if cache_entry.server == current_server
|
||||
&& cache_entry.created_at.elapsed() < CACHE_TTL
|
||||
{
|
||||
return cache_entry.manager.clone();
|
||||
return cache_entry.manager;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,13 +76,16 @@ impl MihomoManager {
|
||||
// 创建新实例
|
||||
let (current_server, headers) = MihomoManager::get_clash_client_info()
|
||||
.unwrap_or_else(|| (String::new(), HeaderMap::new()));
|
||||
let manager = mihomo_api::MihomoManager::new(current_server.clone(), headers);
|
||||
// ! 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.clone(),
|
||||
manager: manager,
|
||||
created_at: Instant::now(),
|
||||
server: current_server,
|
||||
});
|
||||
|
||||
@@ -242,3 +242,21 @@ pub fn get_encryption_key() -> Result<Vec<u8>> {
|
||||
Ok(key)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn ipc_path() -> Result<PathBuf> {
|
||||
let res_dir = app_resources_dir()?;
|
||||
Ok(res_dir.join("mihomo.sock"))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn ipc_path() -> Result<PathBuf> {
|
||||
let res_dir = app_resources_dir()?;
|
||||
Ok(res_dir.join("mihomo.sock"))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn ipc_path() -> Result<PathBuf> {
|
||||
let res_dir = app_resources_dir()?;
|
||||
Ok(res_dir.join(r"\\.\pipe\mihomo"))
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# LOCAL_SOCK="/Users/tunglies/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev.dev/mihomo.sock"
|
||||
LOCAL_SOCK="/Users/tunglies/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/mihomo.sock"
|
||||
@@ -1,11 +0,0 @@
|
||||
[package]
|
||||
name = "mihomo_api"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.12.22", features = ["json"] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
tokio = { version = "1.46.1", features = ["rt", "macros", "time"] }
|
||||
|
||||
[dev-dependencies]
|
||||
@@ -1,147 +0,0 @@
|
||||
use reqwest::{Method, header::HeaderMap};
|
||||
use serde_json::{Value, json};
|
||||
use std::time::Duration;
|
||||
pub mod model;
|
||||
pub use model::MihomoManager;
|
||||
|
||||
impl MihomoManager {
|
||||
pub fn new(mihomo_server: String, headers: HeaderMap) -> Self {
|
||||
let client = reqwest::ClientBuilder::new()
|
||||
.default_headers(headers)
|
||||
.no_proxy()
|
||||
.timeout(Duration::from_secs(15))
|
||||
.pool_max_idle_per_host(5)
|
||||
.pool_idle_timeout(Duration::from_secs(15))
|
||||
.build()
|
||||
.expect("Failed to build reqwest client");
|
||||
|
||||
Self {
|
||||
mihomo_server,
|
||||
client,
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_request(
|
||||
&self,
|
||||
method: Method,
|
||||
url: String,
|
||||
data: Option<serde_json::Value>,
|
||||
) -> Result<serde_json::Value, String> {
|
||||
let client_response = self
|
||||
.client
|
||||
.request(method.clone(), &url)
|
||||
.json(&data.unwrap_or(json!({})))
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let response = match method {
|
||||
Method::PATCH => {
|
||||
let status = client_response.status();
|
||||
if status.as_u16() == 204 {
|
||||
json!({"code": 204})
|
||||
} else {
|
||||
client_response
|
||||
.json::<serde_json::Value>()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
}
|
||||
}
|
||||
Method::PUT => json!(client_response.text().await.map_err(|e| e.to_string())?),
|
||||
_ => client_response
|
||||
.json::<serde_json::Value>()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?,
|
||||
};
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn get_refresh_proxies(&self) -> Result<Value, String> {
|
||||
let url = format!("{}/proxies", self.mihomo_server);
|
||||
let proxies = self.send_request(Method::GET, url, None).await?;
|
||||
Ok(proxies)
|
||||
}
|
||||
|
||||
pub async fn get_providers_proxies(&self) -> Result<Value, String> {
|
||||
let url = format!("{}/providers/proxies", self.mihomo_server);
|
||||
let providers_proxies = self.send_request(Method::GET, url, None).await?;
|
||||
Ok(providers_proxies)
|
||||
}
|
||||
|
||||
pub async fn close_all_connections(&self) -> Result<(), String> {
|
||||
let url = format!("{}/connections", self.mihomo_server);
|
||||
let response = self.send_request(Method::DELETE, url, None).await?;
|
||||
if response["code"] == 204 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(response["message"]
|
||||
.as_str()
|
||||
.unwrap_or("unknown error")
|
||||
.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MihomoManager {
|
||||
pub async fn is_mihomo_running(&self) -> Result<(), String> {
|
||||
let url = format!("{}/version", self.mihomo_server);
|
||||
let _response = self.send_request(Method::GET, url, None).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn put_configs_force(&self, clash_config_path: &str) -> Result<(), String> {
|
||||
let url = format!("{}/configs?force=true", self.mihomo_server);
|
||||
let payload = serde_json::json!({
|
||||
"path": clash_config_path,
|
||||
});
|
||||
let _response = self.send_request(Method::PUT, url, Some(payload)).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn patch_configs(&self, config: serde_json::Value) -> Result<(), String> {
|
||||
let url = format!("{}/configs", self.mihomo_server);
|
||||
let response = self.send_request(Method::PATCH, url, Some(config)).await?;
|
||||
if response["code"] == 204 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(response["message"]
|
||||
.as_str()
|
||||
.unwrap_or("unknown error")
|
||||
.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn test_proxy_delay(
|
||||
&self,
|
||||
name: &str,
|
||||
test_url: Option<String>,
|
||||
timeout: i32,
|
||||
) -> Result<serde_json::Value, String> {
|
||||
let test_url = test_url.unwrap_or("https://cp.cloudflare.com/generate_204".to_string());
|
||||
let url = format!(
|
||||
"{}/proxies/{}/delay?url={}&timeout={}",
|
||||
self.mihomo_server, name, test_url, timeout
|
||||
);
|
||||
let response = self.send_request(Method::GET, url, None).await?;
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn get_connections(&self) -> Result<serde_json::Value, String> {
|
||||
let url = format!("{}/connections", self.mihomo_server);
|
||||
let response = self.send_request(Method::GET, url, None).await?;
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
pub async fn delete_connection(&self, id: &str) -> Result<(), String> {
|
||||
let url = format!("{}/connections/{}", self.mihomo_server, id);
|
||||
let response = self.send_request(Method::DELETE, url, None).await?;
|
||||
if response["code"] == 204 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(response["message"]
|
||||
.as_str()
|
||||
.unwrap_or("unknown error")
|
||||
.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#[derive(Clone)]
|
||||
pub struct MihomoManager {
|
||||
pub(crate) mihomo_server: String,
|
||||
pub(crate) client: reqwest::Client,
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
use reqwest::header::HeaderMap;
|
||||
|
||||
#[test]
|
||||
fn test_mihomo_manager_init() {
|
||||
let _ = mihomo_api::MihomoManager::new("url".into(), HeaderMap::new());
|
||||
assert_eq!(true, true);
|
||||
}
|
||||
Reference in New Issue
Block a user