mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-10 12:22:07 +08:00
Route frontend and tray node selections through the same backend flow for selection, persistence, state refresh, and connection cleanup. Read the group's previous selection before switching and preserve the original rule of closing only connections whose chains contain that selection. Run optional cleanup in the background and keep its failures separate from successful selection. Remove redundant frontend effects and unused IPC commands, and refresh the proxy view for every successful switch. Refs:32095daf90Refs:bea0dde074
118 lines
3.9 KiB
Rust
118 lines
3.9 KiB
Rust
use super::CmdResult;
|
|
use crate::{
|
|
cmd::StringifyErr as _,
|
|
config::Config,
|
|
core::{
|
|
handle::Handle,
|
|
proxy_view::{GroupScope, ProxyViewBuilder, ProxyViewInput, ProxyViewV1},
|
|
},
|
|
};
|
|
use serde_yaml_ng::Mapping;
|
|
use std::collections::{BTreeMap, HashSet};
|
|
|
|
/// Merges one selection pair into fresh backend state to avoid stale-list overwrites.
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn record_selected_node(group_name: String, node: String) -> CmdResult<()> {
|
|
crate::config::profiles::record_selected_node(&group_name, &node)
|
|
.await
|
|
.stringify_err()
|
|
}
|
|
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn switch_proxy_node(group_name: String, proxy_name: String, unfix: bool) -> CmdResult<()> {
|
|
crate::feat::switch_proxy_node(&group_name, &proxy_name, unfix)
|
|
.await
|
|
.stringify_err()
|
|
}
|
|
|
|
fn runtime_group_order(config: Option<&Mapping>) -> Vec<String> {
|
|
let mut seen = HashSet::new();
|
|
|
|
config
|
|
.and_then(|config| config.get("proxy-groups"))
|
|
.and_then(|groups| groups.as_sequence())
|
|
.into_iter()
|
|
.flatten()
|
|
.filter_map(|group| group.get("name"))
|
|
.filter_map(|name| name.as_str())
|
|
.filter(|name| !name.is_empty() && *name != "GLOBAL")
|
|
.filter(|name| seen.insert(*name))
|
|
.map(str::to_owned)
|
|
.collect()
|
|
}
|
|
|
|
/// Mirrors Mihomo: `include-all`/`include-all-providers` replace `use` with every provider, sorted.
|
|
fn runtime_group_scopes(config: Option<&Mapping>) -> BTreeMap<String, GroupScope> {
|
|
let Some(config) = config else {
|
|
return BTreeMap::new();
|
|
};
|
|
let mut all_providers = config
|
|
.get("proxy-providers")
|
|
.and_then(|providers| providers.as_mapping())
|
|
.into_iter()
|
|
.flat_map(|providers| providers.keys())
|
|
.filter_map(|name| name.as_str())
|
|
.map(str::to_owned)
|
|
.collect::<Vec<_>>();
|
|
all_providers.sort();
|
|
let flag = |group: &Mapping, key: &str| group.get(key).and_then(|value| value.as_bool()) == Some(true);
|
|
|
|
config
|
|
.get("proxy-groups")
|
|
.and_then(|groups| groups.as_sequence())
|
|
.into_iter()
|
|
.flatten()
|
|
.filter_map(|group| group.as_mapping())
|
|
.filter_map(|group| {
|
|
let name = group.get("name")?.as_str()?.to_owned();
|
|
let providers = if flag(group, "include-all") || flag(group, "include-all-providers") {
|
|
all_providers.clone()
|
|
} else {
|
|
group
|
|
.get("use")
|
|
.and_then(|providers| providers.as_sequence())
|
|
.into_iter()
|
|
.flatten()
|
|
.filter_map(|provider| provider.as_str())
|
|
.map(str::to_owned)
|
|
.collect()
|
|
};
|
|
let exclude_types = group
|
|
.get("exclude-type")
|
|
.and_then(|types| types.as_str())
|
|
.filter(|types| !types.is_empty())
|
|
.map(|types| types.split('|').map(str::to_owned).collect())
|
|
.unwrap_or_default();
|
|
Some((
|
|
name,
|
|
GroupScope {
|
|
providers,
|
|
exclude_types,
|
|
},
|
|
))
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
#[tauri::command]
|
|
#[specta::specta]
|
|
pub async fn get_proxy_view() -> CmdResult<ProxyViewV1> {
|
|
let runtime = Config::runtime().await;
|
|
let latest_runtime = runtime.latest_arc();
|
|
let runtime_group_order = runtime_group_order(latest_runtime.config.as_ref());
|
|
let group_scopes = runtime_group_scopes(latest_runtime.config.as_ref());
|
|
|
|
let mihomo = Handle::mihomo();
|
|
let (proxies, providers) = tokio::join!(mihomo.get_proxies(), mihomo.get_proxy_providers(),);
|
|
let proxies = proxies.stringify_err()?;
|
|
|
|
Ok(ProxyViewBuilder::build(ProxyViewInput {
|
|
runtime_group_order,
|
|
group_scopes,
|
|
proxies,
|
|
providers: providers.ok(),
|
|
}))
|
|
}
|