feat(proxy): add proxy commands and integrate with API

Add new proxy.rs module with get_proxies and get_providers_proxies commands.
Update mod.rs and lib.rs to re-export and register proxy commands.
Update API.ts to use invoke for proxy commands.
Minor formatting improvements in module/mihomo.rs.
This commit is contained in:
Tunglies 2025-03-04 01:01:24 +08:00
parent 3b69465016
commit 1ba688727e
5 changed files with 81 additions and 29 deletions

View File

@ -15,6 +15,7 @@ pub mod verge;
pub mod runtime;
pub mod save_profile;
pub mod system;
pub mod proxy;
// Re-export all command functions for backwards compatibility
pub use profile::*;
@ -27,4 +28,5 @@ pub use clash::*;
pub use verge::*;
pub use runtime::*;
pub use save_profile::*;
pub use system::*;
pub use system::*;
pub use proxy::*;

View File

@ -0,0 +1,35 @@
use super::CmdResult;
use crate::module::mihomo::MihomoManager;
use tauri::async_runtime;
#[tauri::command]
pub async fn get_proxies() -> CmdResult<serde_json::Value> {
let proxies = async_runtime::spawn_blocking(|| {
let rt = tokio::runtime::Runtime::new().unwrap();
let manager = MihomoManager::new();
{
let mut write_guard = manager.write();
rt.block_on(write_guard.refresh_proxies());
}
let read_guard = manager.read();
read_guard.fetch_proxies().clone()
})
.await.map_err(|e| e.to_string())?;
Ok(proxies)
}
#[tauri::command]
pub async fn get_providers_proxies() -> CmdResult<serde_json::Value> {
let providers_proxies = async_runtime::spawn_blocking(|| {
let rt = tokio::runtime::Runtime::new().unwrap();
let manager = MihomoManager::new();
{
let mut write_guard = manager.write();
rt.block_on(write_guard.refresh_providers_proxies());
}
let read_guard = manager.read();
read_guard.fetch_providers_proxies().clone()
})
.await.map_err(|e| e.to_string())?;
Ok(providers_proxies)
}

View File

@ -162,6 +162,8 @@ pub fn run() {
cmd::get_runtime_logs,
cmd::invoke_uwp_tool,
cmd::copy_clash_env,
cmd::get_proxies,
cmd::get_providers_proxies,
// verge
cmd::get_verge_config,
cmd::patch_verge_config,

View File

@ -1,8 +1,7 @@
use std::sync::Arc;
use crate::model::api::mihomo::MihomoAPICaller;
use once_cell::sync::OnceCell;
use parking_lot::RwLock;
use crate::model::api::mihomo::MihomoAPICaller;
use std::sync::Arc;
#[allow(unused)]
pub struct MihomoManager {
@ -34,20 +33,27 @@ impl MihomoManager {
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),
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),
Ok(providers_proxies) => {
self.providers_proxies = providers_proxies;
},
Err(e) => {
log::error!("Failed to get providers proxies: {}", e);
},
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -55,18 +61,21 @@ mod tests {
async fn test_mihomo_manager_singleton() {
let manager1 = MihomoManager::new();
let manager2 = MihomoManager::new();
assert!(Arc::ptr_eq(&manager1, &manager2), "Should return same instance");
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();
@ -87,7 +96,7 @@ mod tests {
#[tokio::test]
async fn test_refresh_providers_proxies() {
let manager = MihomoManager::new();
// Test initial state
{
let data = manager.read();
@ -108,7 +117,7 @@ mod tests {
#[tokio::test]
async fn test_fetch_proxies() {
let manager = MihomoManager::new();
// Test initial state
{
let data = manager.read();
@ -129,7 +138,7 @@ mod tests {
#[tokio::test]
async fn test_fetch_providers_proxies() {
let manager = MihomoManager::new();
// Test initial state
{
let data = manager.read();
@ -146,4 +155,4 @@ mod tests {
// Would need API mocking for more thorough testing
}
}
}
}

View File

@ -1,5 +1,7 @@
import axios, { AxiosInstance } from "axios";
import { getClashInfo } from "./cmds";
import { invoke } from "@tauri-apps/api/core";
import { useLockFn } from "ahooks";
let axiosIns: AxiosInstance = null!;
@ -94,13 +96,18 @@ export const updateProxy = async (group: string, proxy: string) => {
// get proxy
export const getProxiesInner = async () => {
const instance = await getAxios();
const response = await instance.get<any, any>("/proxies");
return (response?.proxies || {}) as Record<string, IProxyItem>;
const response = await invoke<Record<string, IProxyItem>>("get_proxies");
return response.proxies;
};
/// Get the Proxy information
export const getProxies = async () => {
export const getProxies = async (): Promise<{
global: IProxyGroupItem;
direct: IProxyItem;
groups: IProxyGroupItem[];
records: Record<string, IProxyItem>;
proxies: IProxyItem[];
}> => {
const [proxyRecord, providerRecord] = await Promise.all([
getProxiesInner(),
getProxyProviders(),
@ -181,13 +188,10 @@ export const getProxies = async () => {
// get proxy providers
export const getProxyProviders = async () => {
const instance = await getAxios();
const response = await instance.get<any, any>("/providers/proxies");
const providers = (response.providers || {}) as Record<
string,
IProxyProviderItem
>;
const response = await invoke<Record<string, IProxyProviderItem>>(
"get_providers_proxies",
);
const providers = response.providers;
return Object.fromEntries(
Object.entries(providers).filter(([key, item]) => {