mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 03:13:44 +08:00
feat: add Mihomo API modules and manager (#2869)
• Introduce new API caller implementations for Mihomo in model and module layers. • Add configuration and API integration files under /src-tauri/src/config/api and /src-tauri/src/model/api. • Implement a singleton MihomoAPICaller with async API call support and integration tests. • Create a new MihomoManager module to refresh and fetch proxies from the API. • Update Cargo.lock and Cargo.toml with additional dependencies (async-trait, env_logger, mockito, tempfile, etc.) related to the Mihomo API support.
This commit is contained in:
parent
3e53ea7209
commit
3b69465016
134
src-tauri/Cargo.lock
generated
134
src-tauri/Cargo.lock
generated
@ -116,6 +116,56 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.95"
|
||||
@ -191,6 +241,16 @@ dependencies = [
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert-json-diff"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.7.2"
|
||||
@ -1003,6 +1063,7 @@ version = "2.1.2"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"boa_engine",
|
||||
"chrono",
|
||||
@ -1010,12 +1071,14 @@ dependencies = [
|
||||
"delay_timer",
|
||||
"dirs 6.0.0",
|
||||
"dunce",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"getrandom 0.2.15",
|
||||
"image 0.24.9",
|
||||
"imageproc",
|
||||
"log",
|
||||
"log4rs",
|
||||
"mockito",
|
||||
"nanoid",
|
||||
"network-interface",
|
||||
"once_cell",
|
||||
@ -1047,6 +1110,7 @@ dependencies = [
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-updater",
|
||||
"tauri-plugin-window-state",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"tokio-tungstenite 0.26.1",
|
||||
"url",
|
||||
@ -1132,6 +1196,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "2.2.0"
|
||||
@ -1927,6 +1997,29 @@ dependencies = [
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"humantime",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
@ -2924,6 +3017,7 @@ dependencies = [
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa 1.0.14",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
@ -3344,6 +3438,12 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
@ -3845,6 +3945,30 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockito"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "652cd6d169a36eaf9d1e6bce1a221130439a966d7f27858af66a33a66e9c4ee2"
|
||||
dependencies = [
|
||||
"assert-json-diff",
|
||||
"bytes",
|
||||
"colored",
|
||||
"futures-util",
|
||||
"http 1.2.0",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"similar",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "muda"
|
||||
version = "0.15.3"
|
||||
@ -6161,6 +6285,12 @@ version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.11"
|
||||
@ -7002,9 +7132,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.16.0"
|
||||
version = "3.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
|
||||
checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand 2.3.0",
|
||||
|
@ -67,6 +67,7 @@ getrandom = "0.2"
|
||||
tokio-tungstenite = "0.26.1"
|
||||
futures = "0.3"
|
||||
sys-locale = "0.3.1"
|
||||
async-trait = "0.1.86"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.2.0"
|
||||
@ -120,3 +121,8 @@ strip = false # 不剥离符号,保留调试信息
|
||||
[lib]
|
||||
name = "app_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.11.0"
|
||||
mockito = "1.2.0"
|
||||
tempfile = "3.17.1"
|
||||
|
1
src-tauri/src/config/api/mihomo.rs
Normal file
1
src-tauri/src/config/api/mihomo.rs
Normal file
@ -0,0 +1 @@
|
||||
pub const MIHOMO_URL: &str = concat!("http://", "127.0.0.1", ":", "9097");
|
1
src-tauri/src/config/api/mod.rs
Normal file
1
src-tauri/src/config/api/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod mihomo;
|
@ -21,3 +21,6 @@ pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) {
|
||||
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;";
|
||||
}
|
||||
"#;
|
||||
|
||||
|
||||
pub mod api;
|
@ -85,6 +85,7 @@ pub fn use_seq(seq: SeqMap, mut config: Mapping, field: &str) -> Mapping {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[allow(unused_imports)]
|
||||
use serde_yaml::Value;
|
||||
|
||||
#[test]
|
||||
|
20
src-tauri/src/model/api/common.rs
Normal file
20
src-tauri/src/model/api/common.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use reqwest::Client;
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) struct ApiCaller<'a> {
|
||||
pub(crate) url: &'a str,
|
||||
pub(crate) client: Client,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_api_caller() {
|
||||
let _api_caller = ApiCaller {
|
||||
url: "https://example.com",
|
||||
client: Client::new(),
|
||||
};
|
||||
}
|
||||
}
|
5
src-tauri/src/model/api/mihomo.rs
Normal file
5
src-tauri/src/model/api/mihomo.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use super::common::ApiCaller;
|
||||
|
||||
pub struct MihomoAPICaller {
|
||||
pub(crate) caller: ApiCaller<'static>,
|
||||
}
|
2
src-tauri/src/model/api/mod.rs
Normal file
2
src-tauri/src/model/api/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod common;
|
||||
pub mod mihomo;
|
@ -1 +1,2 @@
|
||||
pub mod api;
|
||||
pub mod sysinfo;
|
70
src-tauri/src/module/api/common.rs
Normal file
70
src-tauri/src/module/api/common.rs
Normal file
@ -0,0 +1,70 @@
|
||||
use crate::model::api::common::ApiCaller;
|
||||
use async_trait::async_trait;
|
||||
use reqwest::{
|
||||
header::{HeaderMap, HeaderName, HeaderValue},
|
||||
RequestBuilder,
|
||||
};
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
impl<'a> ApiCaller<'a> {
|
||||
pub async fn send_request(
|
||||
&self,
|
||||
method: &str,
|
||||
path: &str,
|
||||
body: Option<&str>,
|
||||
headers: Option<Vec<(&str, &str)>>,
|
||||
) -> Result<String, String> {
|
||||
let full_url = format!("{}{}", self.url, path); // 拼接完整 URL
|
||||
let mut request: RequestBuilder = match method {
|
||||
"GET" => self.client.get(&full_url),
|
||||
"POST" => self
|
||||
.client
|
||||
.post(&full_url)
|
||||
.body(body.unwrap_or("").to_string()),
|
||||
"PUT" => self
|
||||
.client
|
||||
.put(&full_url)
|
||||
.body(body.unwrap_or("").to_string()),
|
||||
"DELETE" => self.client.delete(&full_url),
|
||||
_ => return Err("Unsupported HTTP method".to_string()),
|
||||
};
|
||||
|
||||
// 处理 headers
|
||||
if let Some(hdrs) = headers {
|
||||
let mut header_map = HeaderMap::new();
|
||||
for (key, value) in hdrs {
|
||||
if let (Ok(header_name), Ok(header_value)) = (
|
||||
HeaderName::from_bytes(key.as_bytes()),
|
||||
HeaderValue::from_str(value),
|
||||
) {
|
||||
header_map.insert(header_name, header_value);
|
||||
}
|
||||
}
|
||||
request = request.headers(header_map);
|
||||
}
|
||||
|
||||
let response = request.send().await.map_err(|e| e.to_string())?;
|
||||
response.text().await.map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[async_trait]
|
||||
pub trait ApiCallerTrait: Send + Sync {
|
||||
async fn call_api<T>(
|
||||
&self,
|
||||
method: &str,
|
||||
path: &str,
|
||||
body: Option<&str>,
|
||||
headers: Option<Vec<(&str, &str)>>
|
||||
) -> Result<T, String>
|
||||
where
|
||||
T: DeserializeOwned + Send + Sync;
|
||||
|
||||
fn parse_json_response<T>(json_str: &str) -> Result<T, String>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
serde_json::from_str(json_str).map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
108
src-tauri/src/module/api/mihomo.rs
Normal file
108
src-tauri/src/module/api/mihomo.rs
Normal file
@ -0,0 +1,108 @@
|
||||
use super::common::ApiCallerTrait;
|
||||
use crate::config::api::mihomo::MIHOMO_URL;
|
||||
use crate::model::api::common::ApiCaller;
|
||||
use crate::model::api::mihomo::MihomoAPICaller;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::RwLock;
|
||||
use reqwest::Client;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::sync::Arc;
|
||||
|
||||
impl MihomoAPICaller {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Arc<RwLock<Self>> {
|
||||
static INSTANCE: OnceCell<Arc<RwLock<MihomoAPICaller>>> = OnceCell::new();
|
||||
INSTANCE
|
||||
.get_or_init(|| {
|
||||
let client = Client::new();
|
||||
Arc::new(RwLock::new(MihomoAPICaller {
|
||||
caller: ApiCaller {
|
||||
url: MIHOMO_URL,
|
||||
client,
|
||||
},
|
||||
}))
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ApiCallerTrait for MihomoAPICaller {
|
||||
async fn call_api<T>(
|
||||
&self,
|
||||
method: &str,
|
||||
path: &str,
|
||||
body: Option<&str>,
|
||||
headers: Option<Vec<(&str, &str)>>,
|
||||
) -> Result<T, String>
|
||||
where
|
||||
T: DeserializeOwned + Send + Sync,
|
||||
{
|
||||
let response = self
|
||||
.caller
|
||||
.send_request(method, path, body, headers)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
Self::parse_json_response::<T>(&response)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl MihomoAPICaller {
|
||||
pub async fn get_proxies() -> Result<serde_json::Value, String> {
|
||||
Self::new()
|
||||
.read()
|
||||
.call_api("GET", "/proxies", None, None)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_providers_proxies() -> Result<serde_json::Value, String> {
|
||||
Self::new()
|
||||
.read()
|
||||
.call_api("GET", "/providers/proxies", None, None)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_api_singleton() {
|
||||
let mihomo_api_caller1 = MihomoAPICaller::new();
|
||||
let mihomo_api_caller2 = MihomoAPICaller::new();
|
||||
assert!(Arc::ptr_eq(&mihomo_api_caller1, &mihomo_api_caller2));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_api_version() {
|
||||
let mihomo_caller = MihomoAPICaller::new();
|
||||
let response: Result<serde_json::Value, String> = mihomo_caller
|
||||
.read()
|
||||
.call_api("GET", "/version", None, None)
|
||||
.await;
|
||||
assert!(response.is_ok());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_get_proxies() {
|
||||
let response = MihomoAPICaller::get_proxies().await;
|
||||
assert!(response.is_ok());
|
||||
if let Ok(proxies) = &response {
|
||||
assert!(!proxies.get("proxies").is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_get_providers_proxies() {
|
||||
let response = MihomoAPICaller::get_providers_proxies().await;
|
||||
println!("{:?}", response);
|
||||
assert!(response.is_ok());
|
||||
if let Ok(providers_proxies) = &response {
|
||||
assert!(!providers_proxies.get("providers").is_none());
|
||||
}
|
||||
}
|
||||
}
|
2
src-tauri/src/module/api/mod.rs
Normal file
2
src-tauri/src/module/api/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod common;
|
||||
pub mod mihomo;
|
149
src-tauri/src/module/mihomo.rs
Normal file
149
src-tauri/src/module/mihomo.rs
Normal file
@ -0,0 +1,149 @@
|
||||
use std::sync::Arc;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::RwLock;
|
||||
use crate::model::api::mihomo::MihomoAPICaller;
|
||||
|
||||
|
||||
#[allow(unused)]
|
||||
pub struct MihomoManager {
|
||||
proxies: serde_json::Value,
|
||||
providers_proxies: serde_json::Value,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl MihomoManager {
|
||||
pub fn new() -> Arc<RwLock<Self>> {
|
||||
static INSTANCE: OnceCell<Arc<RwLock<MihomoManager>>> = OnceCell::new();
|
||||
INSTANCE
|
||||
.get_or_init(|| {
|
||||
Arc::new(RwLock::new(MihomoManager {
|
||||
proxies: serde_json::Value::Null,
|
||||
providers_proxies: serde_json::Value::Null,
|
||||
}))
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn fetch_proxies(&self) -> &serde_json::Value {
|
||||
&self.proxies
|
||||
}
|
||||
|
||||
pub fn fetch_providers_proxies(&self) -> &serde_json::Value {
|
||||
&self.providers_proxies
|
||||
}
|
||||
|
||||
pub async fn refresh_proxies(&mut self) {
|
||||
match MihomoAPICaller::get_proxies().await {
|
||||
Ok(proxies) => self.proxies = proxies,
|
||||
Err(e) => log::error!("Failed to get proxies: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn refresh_providers_proxies(&mut self) {
|
||||
match MihomoAPICaller::get_providers_proxies().await {
|
||||
Ok(providers_proxies) => self.providers_proxies = providers_proxies,
|
||||
Err(e) => log::error!("Failed to get providers proxies: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[tokio::test]
|
||||
async fn test_mihomo_manager_singleton() {
|
||||
let manager1 = MihomoManager::new();
|
||||
let manager2 = MihomoManager::new();
|
||||
|
||||
assert!(Arc::ptr_eq(&manager1, &manager2), "Should return same instance");
|
||||
|
||||
let manager = manager1.read();
|
||||
assert!(manager.proxies.is_null());
|
||||
assert!(manager.providers_proxies.is_null());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_refresh_proxies() {
|
||||
let manager = MihomoManager::new();
|
||||
|
||||
// Test initial state
|
||||
{
|
||||
let data = manager.read();
|
||||
assert!(data.proxies.is_null());
|
||||
}
|
||||
|
||||
// Test refresh
|
||||
{
|
||||
let mut data = manager.write();
|
||||
data.refresh_proxies().await;
|
||||
// Note: Since this depends on external API call,
|
||||
// we can only verify that the refresh call completes
|
||||
// without panicking. For more thorough testing,
|
||||
// we would need to mock the API caller.
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_refresh_providers_proxies() {
|
||||
let manager = MihomoManager::new();
|
||||
|
||||
// Test initial state
|
||||
{
|
||||
let data = manager.read();
|
||||
assert!(data.providers_proxies.is_null());
|
||||
}
|
||||
|
||||
// Test refresh
|
||||
{
|
||||
let mut data = manager.write();
|
||||
data.refresh_providers_proxies().await;
|
||||
// Note: Since this depends on external API call,
|
||||
// we can only verify that the refresh call completes
|
||||
// without panicking. For more thorough testing,
|
||||
// we would need to mock the API caller.
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_fetch_proxies() {
|
||||
let manager = MihomoManager::new();
|
||||
|
||||
// Test initial state
|
||||
{
|
||||
let data = manager.read();
|
||||
let proxies = data.fetch_proxies();
|
||||
assert!(proxies.is_null());
|
||||
}
|
||||
|
||||
// Test after refresh
|
||||
{
|
||||
let mut data = manager.write();
|
||||
data.refresh_proxies().await;
|
||||
let _proxies = data.fetch_proxies();
|
||||
// Can only verify the method returns without panicking
|
||||
// Would need API mocking for more thorough testing
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_fetch_providers_proxies() {
|
||||
let manager = MihomoManager::new();
|
||||
|
||||
// Test initial state
|
||||
{
|
||||
let data = manager.read();
|
||||
let providers_proxies = data.fetch_providers_proxies();
|
||||
assert!(providers_proxies.is_null());
|
||||
}
|
||||
|
||||
// Test after refresh
|
||||
{
|
||||
let mut data = manager.write();
|
||||
data.refresh_providers_proxies().await;
|
||||
let _providers_proxies = data.fetch_providers_proxies();
|
||||
// Can only verify the method returns without panicking
|
||||
// Would need API mocking for more thorough testing
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1,3 @@
|
||||
pub mod api;
|
||||
pub mod sysinfo;
|
||||
pub mod mihomo;
|
Loading…
x
Reference in New Issue
Block a user