mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
fix: refactor proxy fetching to use command methods and improve error handling
This commit is contained in:
@@ -15,11 +15,11 @@ const PROVIDERS_REFRESH_INTERVAL: Duration = Duration::from_secs(60);
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_proxies() -> CmdResult<serde_json::Value> {
|
pub async fn get_proxies() -> CmdResult<serde_json::Value> {
|
||||||
let manager = IpcManager::global();
|
|
||||||
let cache = ProxyRequestCache::global();
|
let cache = ProxyRequestCache::global();
|
||||||
let key = ProxyRequestCache::make_key("proxies", "default");
|
let key = ProxyRequestCache::make_key("proxies", "default");
|
||||||
let value = cache
|
let value = cache
|
||||||
.get_or_fetch(key, PROXIES_REFRESH_INTERVAL, || async {
|
.get_or_fetch(key, PROXIES_REFRESH_INTERVAL, || async {
|
||||||
|
let manager = IpcManager::global();
|
||||||
manager.get_proxies().await.unwrap_or_else(|e| {
|
manager.get_proxies().await.unwrap_or_else(|e| {
|
||||||
logging!(error, Type::Cmd, "Failed to fetch proxies: {e}");
|
logging!(error, Type::Cmd, "Failed to fetch proxies: {e}");
|
||||||
serde_json::Value::Object(serde_json::Map::new())
|
serde_json::Value::Object(serde_json::Map::new())
|
||||||
@@ -40,11 +40,11 @@ pub async fn force_refresh_proxies() -> CmdResult<serde_json::Value> {
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_providers_proxies() -> CmdResult<serde_json::Value> {
|
pub async fn get_providers_proxies() -> CmdResult<serde_json::Value> {
|
||||||
let manager = IpcManager::global();
|
|
||||||
let cache = ProxyRequestCache::global();
|
let cache = ProxyRequestCache::global();
|
||||||
let key = ProxyRequestCache::make_key("providers", "default");
|
let key = ProxyRequestCache::make_key("providers", "default");
|
||||||
let value = cache
|
let value = cache
|
||||||
.get_or_fetch(key, PROVIDERS_REFRESH_INTERVAL, || async {
|
.get_or_fetch(key, PROVIDERS_REFRESH_INTERVAL, || async {
|
||||||
|
let manager = IpcManager::global();
|
||||||
manager.get_providers_proxies().await.unwrap_or_else(|e| {
|
manager.get_providers_proxies().await.unwrap_or_else(|e| {
|
||||||
logging!(error, Type::Cmd, "Failed to fetch provider proxies: {e}");
|
logging!(error, Type::Cmd, "Failed to fetch provider proxies: {e}");
|
||||||
serde_json::Value::Object(serde_json::Map::new())
|
serde_json::Value::Object(serde_json::Map::new())
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use tauri::Emitter;
|
|||||||
pub mod speed_rate;
|
pub mod speed_rate;
|
||||||
use crate::ipc::Rate;
|
use crate::ipc::Rate;
|
||||||
use crate::process::AsyncHandler;
|
use crate::process::AsyncHandler;
|
||||||
|
use crate::state::proxy::ProxyRequestCache;
|
||||||
use crate::{
|
use crate::{
|
||||||
cmd,
|
cmd,
|
||||||
config::Config,
|
config::Config,
|
||||||
@@ -285,13 +286,14 @@ impl Tray {
|
|||||||
let is_lightweight_mode = is_in_lightweight_mode();
|
let is_lightweight_mode = is_in_lightweight_mode();
|
||||||
|
|
||||||
// 获取代理节点
|
// 获取代理节点
|
||||||
let proxy_nodes_data = match IpcManager::global().get_proxies().await {
|
let proxy_nodes_data = cmd::get_proxies().await.unwrap_or_else(|e| {
|
||||||
Ok(data) => data,
|
logging!(
|
||||||
Err(e) => {
|
error,
|
||||||
log::warn!(target: "app", "获取代理节点数据失败: {}", e);
|
Type::Cmd,
|
||||||
serde_json::Value::Object(serde_json::Map::new())
|
"Failed to fetch proxies for tray menu: {e}"
|
||||||
}
|
);
|
||||||
};
|
serde_json::Value::Object(serde_json::Map::new())
|
||||||
|
});
|
||||||
|
|
||||||
match app_handle.tray_by_id("main") {
|
match app_handle.tray_by_id("main") {
|
||||||
Some(tray) => {
|
Some(tray) => {
|
||||||
@@ -576,17 +578,13 @@ async fn create_tray_menu(
|
|||||||
|
|
||||||
// 获取当前配置文件的选中代理组信息
|
// 获取当前配置文件的选中代理组信息
|
||||||
let current_profile_selected = {
|
let current_profile_selected = {
|
||||||
let profiles = Config::profiles().await;
|
let profiles_config = Config::profiles().await;
|
||||||
let profiles = profiles.latest_ref();
|
let profiles_ref = profiles_config.latest_ref();
|
||||||
if let Some(current_profile_uid) = profiles.get_current() {
|
profiles_ref
|
||||||
if let Ok(profile) = profiles.get_item(¤t_profile_uid) {
|
.get_current()
|
||||||
profile.selected.clone().unwrap_or_default()
|
.and_then(|uid| profiles_ref.get_item(&uid).ok())
|
||||||
} else {
|
.and_then(|profile| profile.selected.clone())
|
||||||
Vec::new()
|
.unwrap_or_default()
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let version = env!("CARGO_PKG_VERSION");
|
let version = env!("CARGO_PKG_VERSION");
|
||||||
@@ -639,113 +637,99 @@ async fn create_tray_menu(
|
|||||||
let proxy_submenus: Vec<Submenu<Wry>> = {
|
let proxy_submenus: Vec<Submenu<Wry>> = {
|
||||||
let mut submenus = Vec::new();
|
let mut submenus = Vec::new();
|
||||||
|
|
||||||
//
|
|
||||||
if let Some(proxies) = proxy_nodes_data.get("proxies").and_then(|v| v.as_object()) {
|
if let Some(proxies) = proxy_nodes_data.get("proxies").and_then(|v| v.as_object()) {
|
||||||
for (group_name, group_data) in proxies.iter() {
|
for (group_name, group_data) in proxies.iter() {
|
||||||
if let Some(all_proxies) = group_data.get("all").and_then(|v| v.as_array()) {
|
// Filter groups based on mode
|
||||||
// 在全局模式下只显示GLOBAL组,在规则模式下显示所有Selector类型的代理组
|
let should_show = match mode {
|
||||||
let should_show_group = if mode == "global" {
|
"global" => group_name == "GLOBAL",
|
||||||
group_name == "GLOBAL"
|
_ => group_name != "GLOBAL",
|
||||||
} else {
|
};
|
||||||
group_name != "GLOBAL"
|
|
||||||
};
|
|
||||||
|
|
||||||
if !should_show_group {
|
if !should_show {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let now_proxy = group_data.get("now").and_then(|v| v.as_str()).unwrap_or("");
|
let Some(all_proxies) = group_data.get("all").and_then(|v| v.as_array()) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
// 每个代理组创建子菜单项
|
let now_proxy = group_data.get("now").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
let mut group_items = Vec::new();
|
|
||||||
|
|
||||||
for proxy_name in all_proxies.iter() {
|
// Create proxy items
|
||||||
if let Some(proxy_str) = proxy_name.as_str() {
|
let group_items: Vec<CheckMenuItem<Wry>> = all_proxies
|
||||||
let is_selected = proxy_str == now_proxy;
|
.iter()
|
||||||
let item_id = format!("proxy_{}_{}", group_name, proxy_str);
|
.filter_map(|proxy_name| proxy_name.as_str())
|
||||||
|
.filter_map(|proxy_str| {
|
||||||
|
let is_selected = proxy_str == now_proxy;
|
||||||
|
let item_id = format!("proxy_{}_{}", group_name, proxy_str);
|
||||||
|
|
||||||
let display_text = {
|
// Get delay for display
|
||||||
if let Some(proxy_detail) = proxies.get(proxy_str) {
|
let delay_text = proxies
|
||||||
if let Some(history) =
|
.get(proxy_str)
|
||||||
proxy_detail.get("history").and_then(|h| h.as_array())
|
.and_then(|p| p.get("history"))
|
||||||
{
|
.and_then(|h| h.as_array())
|
||||||
if let Some(last_record) = history.last() {
|
.and_then(|h| h.last())
|
||||||
if let Some(delay) =
|
.and_then(|r| r.get("delay"))
|
||||||
last_record.get("delay").and_then(|d| d.as_i64())
|
.and_then(|d| d.as_i64())
|
||||||
{
|
.map(|delay| match delay {
|
||||||
if delay == -1 {
|
-1 => "-ms".to_string(),
|
||||||
format!("{} | -ms", proxy_str)
|
delay if delay >= 10000 => "-ms".to_string(),
|
||||||
} else if delay >= 10000 {
|
_ => format!("{}ms", delay),
|
||||||
format!("{} | -1ms", proxy_str)
|
})
|
||||||
} else {
|
.unwrap_or_else(|| "-ms".to_string());
|
||||||
format!("{} | {}ms", proxy_str, delay)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
format!("{} | -ms ", proxy_str)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
format!("{} | -ms ", proxy_str)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
format!("{} | -ms", proxy_str)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
format!("{} | -ms ", proxy_str)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match CheckMenuItem::with_id(
|
let display_text = format!("{} | {}", proxy_str, delay_text);
|
||||||
app_handle,
|
|
||||||
item_id,
|
|
||||||
display_text, // 显示包含延迟的节点名
|
|
||||||
true,
|
|
||||||
is_selected,
|
|
||||||
None::<&str>,
|
|
||||||
) {
|
|
||||||
Ok(item) => group_items.push(item),
|
|
||||||
Err(e) => log::warn!(target: "app", "创建代理菜单项失败: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建代理组子菜单
|
CheckMenuItem::with_id(
|
||||||
if !group_items.is_empty() {
|
|
||||||
let group_items_refs: Vec<&dyn IsMenuItem<Wry>> = group_items
|
|
||||||
.iter()
|
|
||||||
.map(|item| item as &dyn IsMenuItem<Wry>)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// 判断当前代理组是否为真正在使用中的组
|
|
||||||
let is_group_active = if mode == "global" {
|
|
||||||
group_name == "GLOBAL" && !now_proxy.is_empty()
|
|
||||||
} else if mode == "direct" {
|
|
||||||
// 直连模式下 不显示任何勾选
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
let is_user_selected = current_profile_selected
|
|
||||||
.iter()
|
|
||||||
.any(|selected| selected.name.as_deref() == Some(group_name));
|
|
||||||
is_user_selected && !now_proxy.is_empty()
|
|
||||||
};
|
|
||||||
|
|
||||||
// 如果组处于活动状态,在组名前添加勾选标记
|
|
||||||
let group_display_name = if is_group_active {
|
|
||||||
format!("✓ {}", group_name)
|
|
||||||
} else {
|
|
||||||
group_name.to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
match Submenu::with_id_and_items(
|
|
||||||
app_handle,
|
app_handle,
|
||||||
format!("proxy_group_{}", group_name),
|
item_id,
|
||||||
group_display_name, // 使用带勾选标记的组名
|
display_text,
|
||||||
true,
|
true,
|
||||||
&group_items_refs,
|
is_selected,
|
||||||
) {
|
None::<&str>,
|
||||||
Ok(submenu) => submenus.push(submenu),
|
)
|
||||||
Err(e) => log::warn!(target: "app", "创建代理组子菜单失败: {}", e),
|
.map_err(|e| log::warn!(target: "app", "创建代理菜单项失败: {}", e))
|
||||||
}
|
.ok()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if group_items.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if group is active
|
||||||
|
let is_group_active = match mode {
|
||||||
|
"global" => group_name == "GLOBAL" && !now_proxy.is_empty(),
|
||||||
|
"direct" => false,
|
||||||
|
_ => {
|
||||||
|
current_profile_selected
|
||||||
|
.iter()
|
||||||
|
.any(|s| s.name.as_deref() == Some(group_name))
|
||||||
|
&& !now_proxy.is_empty()
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let group_display_name = if is_group_active {
|
||||||
|
format!("✓ {}", group_name)
|
||||||
|
} else {
|
||||||
|
group_name.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let group_items_refs: Vec<&dyn IsMenuItem<Wry>> = group_items
|
||||||
|
.iter()
|
||||||
|
.map(|item| item as &dyn IsMenuItem<Wry>)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if let Ok(submenu) = Submenu::with_id_and_items(
|
||||||
|
app_handle,
|
||||||
|
format!("proxy_group_{}", group_name),
|
||||||
|
group_display_name,
|
||||||
|
true,
|
||||||
|
&group_items_refs,
|
||||||
|
) {
|
||||||
|
submenus.push(submenu);
|
||||||
|
} else {
|
||||||
|
log::warn!(target: "app", "创建代理组子菜单失败: {}", group_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1050,17 +1034,6 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
|
|||||||
let group_name = parts[1];
|
let group_name = parts[1];
|
||||||
let proxy_name = parts[2];
|
let proxy_name = parts[2];
|
||||||
|
|
||||||
let current_mode = {
|
|
||||||
Config::clash()
|
|
||||||
.await
|
|
||||||
.latest_ref()
|
|
||||||
.0
|
|
||||||
.get("mode")
|
|
||||||
.map(|val| val.as_str().unwrap_or("rule"))
|
|
||||||
.unwrap_or("rule")
|
|
||||||
.to_owned()
|
|
||||||
};
|
|
||||||
|
|
||||||
match cmd::proxy::update_proxy_and_sync(
|
match cmd::proxy::update_proxy_and_sync(
|
||||||
group_name.to_string(),
|
group_name.to_string(),
|
||||||
proxy_name.to_string(),
|
proxy_name.to_string(),
|
||||||
@@ -1068,31 +1041,20 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) {
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
log::info!(target: "app", " {} -> {} (模式: {})", group_name, proxy_name, current_mode);
|
log::info!(target: "app", "切换代理成功: {} -> {}", group_name, proxy_name);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!(target: "app", " {} -> {}, 错误: {:?}", group_name, proxy_name, e);
|
log::error!(target: "app", "切换代理失败: {} -> {}, 错误: {:?}", group_name, proxy_name, e);
|
||||||
|
|
||||||
match IpcManager::global()
|
// Fallback to IPC update
|
||||||
|
if let Ok(_) = IpcManager::global()
|
||||||
.update_proxy(group_name, proxy_name)
|
.update_proxy(group_name, proxy_name)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_) => {
|
log::info!(target: "app", "代理切换回退成功: {} -> {}", group_name, proxy_name);
|
||||||
log::info!(target: "app", " {} -> {}", group_name, proxy_name);
|
|
||||||
|
|
||||||
if let Err(e) = Tray::global().update_menu().await {
|
if let Some(app_handle) = handle::Handle::global().app_handle() {
|
||||||
log::warn!(target: "app", "托盘菜单更新失败: {e}");
|
let _ = app_handle.emit("verge://force-refresh-proxies", ());
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(app_handle) = handle::Handle::global().app_handle()
|
|
||||||
{
|
|
||||||
let _ =
|
|
||||||
app_handle.emit("verge://force-refresh-proxies", ());
|
|
||||||
let _ = app_handle.emit("verge://refresh-proxy-config", ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e2) => {
|
|
||||||
log::error!(target: "app", "托盘代理切换回退也失败: {} -> {}, 错误: {}", group_name, proxy_name, e2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user