mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 00:35:38 +08:00
Add Func 链式代理 (#4624)
* 添加链式代理gui和语言支持 在Iruntime中添跟新链式代理配置方法 同时添加了cmd * 修复读取运行时代理链配置文件bug * t * 完成链式代理配置构造 * 修复获取链式代理运行时配置的bug * 完整的链式代理功能
This commit is contained in:
@@ -76,6 +76,7 @@ pub async fn sync_tray_proxy_selection() -> CmdResult<()> {
|
||||
pub async fn update_proxy_and_sync(group: String, proxy: String) -> CmdResult<()> {
|
||||
match IpcManager::global().update_proxy(&group, &proxy).await {
|
||||
Ok(_) => {
|
||||
// println!("Proxy updated successfully: {} -> {}", group,proxy);
|
||||
logging!(
|
||||
info,
|
||||
Type::Cmd,
|
||||
@@ -107,6 +108,7 @@ pub async fn update_proxy_and_sync(group: String, proxy: String) -> CmdResult<()
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
println!("1111111111111111");
|
||||
logging!(
|
||||
error,
|
||||
Type::Cmd,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::CmdResult;
|
||||
use crate::{config::*, wrap_err};
|
||||
use crate::{config::*, core::CoreManager, log_err, wrap_err};
|
||||
use anyhow::Context;
|
||||
use serde_yaml_ng::Mapping;
|
||||
use std::collections::HashMap;
|
||||
@@ -15,6 +15,7 @@ pub async fn get_runtime_config() -> CmdResult<Option<Mapping>> {
|
||||
pub async fn get_runtime_yaml() -> CmdResult<String> {
|
||||
let runtime = Config::runtime().await;
|
||||
let runtime = runtime.latest_ref();
|
||||
|
||||
let config = runtime.config.as_ref();
|
||||
wrap_err!(
|
||||
config
|
||||
@@ -35,3 +36,90 @@ pub async fn get_runtime_exists() -> CmdResult<Vec<String>> {
|
||||
pub async fn get_runtime_logs() -> CmdResult<HashMap<String, Vec<(String, String)>>> {
|
||||
Ok(Config::runtime().await.latest_ref().chain_logs.clone())
|
||||
}
|
||||
|
||||
/// 读取运行时链式代理配置
|
||||
#[tauri::command]
|
||||
pub async fn get_runtime_proxy_chain_config() -> CmdResult<String> {
|
||||
let runtime = Config::runtime().await;
|
||||
let runtime = runtime.latest_ref();
|
||||
|
||||
let config = wrap_err!(
|
||||
runtime
|
||||
.config
|
||||
.as_ref()
|
||||
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
|
||||
)?;
|
||||
|
||||
if let (
|
||||
Some(serde_yaml_ng::Value::Sequence(proxies)),
|
||||
Some(serde_yaml_ng::Value::Sequence(proxy_groups)),
|
||||
) = (config.get("proxies"), config.get("proxy-groups"))
|
||||
{
|
||||
let mut proxy_name = None;
|
||||
let mut proxies_chain = Vec::new();
|
||||
|
||||
let proxy_chain_groups = proxy_groups
|
||||
.iter()
|
||||
.filter_map(
|
||||
|proxy_group| match proxy_group.get("name").and_then(|n| n.as_str()) {
|
||||
Some("proxy_chain") => {
|
||||
if let Some(serde_yaml_ng::Value::Sequence(ps)) = proxy_group.get("proxies")
|
||||
&& let Some(x) = ps.first()
|
||||
{
|
||||
proxy_name = Some(x); //插入出口节点名字
|
||||
}
|
||||
Some(proxy_group.to_owned())
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
)
|
||||
.collect::<Vec<serde_yaml_ng::Value>>();
|
||||
|
||||
while let Some(proxy) = proxies.iter().find(|proxy| {
|
||||
if let serde_yaml_ng::Value::Mapping(proxy_map) = proxy {
|
||||
proxy_map.get("name") == proxy_name && proxy_map.get("dialer-proxy").is_some()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
proxies_chain.push(proxy.to_owned());
|
||||
proxy_name = proxy.get("dialer-proxy");
|
||||
}
|
||||
|
||||
if let Some(entry_proxy) = proxies.iter().find(|proxy| proxy.get("name") == proxy_name) {
|
||||
proxies_chain.push(entry_proxy.to_owned());
|
||||
}
|
||||
|
||||
proxies_chain.reverse();
|
||||
|
||||
let mut config: HashMap<String, Vec<serde_yaml_ng::Value>> = HashMap::new();
|
||||
config.insert("proxies".to_string(), proxies_chain);
|
||||
config.insert("proxy-groups".to_string(), proxy_chain_groups);
|
||||
|
||||
wrap_err!(serde_yaml_ng::to_string(&config).context("YAML generation failed"))
|
||||
} else {
|
||||
wrap_err!(Err(anyhow::anyhow!(
|
||||
"failed to get proxies or proxy-groups".to_string()
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
/// 更新运行时链式代理配置
|
||||
#[tauri::command]
|
||||
pub async fn update_proxy_chain_config_in_runtime(
|
||||
proxy_chain_config: Option<serde_yaml_ng::Value>,
|
||||
) -> CmdResult<()> {
|
||||
{
|
||||
let runtime = Config::runtime().await;
|
||||
let mut draft = runtime.draft_mut();
|
||||
draft.update_proxy_chain_config(proxy_chain_config);
|
||||
drop(draft);
|
||||
runtime.apply();
|
||||
}
|
||||
|
||||
// 生成新的运行配置文件并通知 Clash 核心重新加载
|
||||
let run_path = wrap_err!(Config::generate_file(ConfigType::Run).await)?;
|
||||
log_err!(CoreManager::global().put_configs_force(run_path).await);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -46,4 +46,139 @@ impl IRuntime {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//跟新链式代理配置文件
|
||||
/// {
|
||||
/// "proxies":[
|
||||
/// {
|
||||
/// name : 入口节点,
|
||||
/// type: xxx
|
||||
/// server: xxx
|
||||
/// port: xxx
|
||||
/// ports: xxx
|
||||
/// password: xxx
|
||||
/// skip-cert-verify: xxx,
|
||||
/// },
|
||||
/// {
|
||||
/// name : hop_node_1_xxxx,
|
||||
/// type: xxx
|
||||
/// server: xxx
|
||||
/// port: xxx
|
||||
/// ports: xxx
|
||||
/// password: xxx
|
||||
/// skip-cert-verify: xxx,
|
||||
/// dialer-proxy : "入口节点"
|
||||
/// },
|
||||
/// {
|
||||
/// name : 出口节点,
|
||||
/// type: xxx
|
||||
/// server: xxx
|
||||
/// port: xxx
|
||||
/// ports: xxx
|
||||
/// password: xxx
|
||||
/// skip-cert-verify: xxx,
|
||||
/// dialer-proxy : "hop_node_1_xxxx"
|
||||
/// }
|
||||
/// ],
|
||||
/// "proxy-groups" : [
|
||||
/// {
|
||||
/// name : "proxy_chain",
|
||||
/// type: "select",
|
||||
/// proxies ["出口节点"]
|
||||
/// }
|
||||
/// ]
|
||||
/// }
|
||||
///
|
||||
/// 传入none 为删除
|
||||
pub fn update_proxy_chain_config(&mut self, proxy_chain_config: Option<Value>) {
|
||||
if let Some(config) = self.config.as_mut() {
|
||||
// 获取 默认第一的代理组的名字
|
||||
let proxy_group_name =
|
||||
if let Some(Value::Sequence(proxy_groups)) = config.get("proxy-groups") {
|
||||
if let Some(Value::Mapping(proxy_group)) = proxy_groups.first() {
|
||||
if let Some(Value::String(proxy_group_name)) = proxy_group.get("name") {
|
||||
proxy_group_name.to_string()
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
if let Some(Value::Sequence(proxies)) = config.get_mut("proxies") {
|
||||
proxies.iter_mut().for_each(|proxy| {
|
||||
if let Some(proxy) = proxy.as_mapping_mut()
|
||||
&& proxy.get("dialer-proxy").is_some()
|
||||
{
|
||||
proxy.remove("dialer-proxy");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 清除proxy_chain代理组
|
||||
if let Some(Value::Sequence(proxy_groups)) = config.get_mut("proxy-groups") {
|
||||
proxy_groups.retain(|proxy_group| {
|
||||
!matches!(proxy_group.get("name").and_then(|n| n.as_str()), Some(name) if name== "proxy_chain")
|
||||
});
|
||||
}
|
||||
|
||||
// 清除rules
|
||||
if let Some(Value::Sequence(rules)) = config.get_mut("rules") {
|
||||
rules.retain(|rule| rule.as_str() != Some("MATCH,proxy_chain"));
|
||||
rules.push(Value::String(format!("MATCH,{}", proxy_group_name)));
|
||||
}
|
||||
|
||||
// some 则写入新配置
|
||||
// 给proxy添加dialer-proxy字段
|
||||
// 第一个proxy不添加dialer-proxy
|
||||
// 然后第二个开始,dialer-proxy为上一个元素的name
|
||||
if let Some(Value::Sequence(dialer_proxies)) = proxy_chain_config {
|
||||
let mut proxy_chain_group = Mapping::new();
|
||||
|
||||
if let Some(Value::Sequence(proxies)) = config.get_mut("proxies") {
|
||||
for (i, dialer_proxy) in dialer_proxies.iter().enumerate() {
|
||||
if let Some(Value::Mapping(proxy)) = proxies
|
||||
.iter_mut()
|
||||
.find(|proxy| proxy.get("name") == Some(dialer_proxy))
|
||||
{
|
||||
if i != 0
|
||||
&& let Some(dialer_proxy) = dialer_proxies.get(i - 1)
|
||||
{
|
||||
proxy.insert("dialer-proxy".into(), dialer_proxy.to_owned());
|
||||
}
|
||||
if i == dialer_proxies.len() - 1 {
|
||||
// 添加proxy-groups
|
||||
proxy_chain_group
|
||||
.insert("name".into(), Value::String("proxy_chain".into()));
|
||||
proxy_chain_group
|
||||
.insert("type".into(), Value::String("select".into()));
|
||||
proxy_chain_group.insert(
|
||||
"proxies".into(),
|
||||
Value::Sequence(vec![dialer_proxy.to_owned()]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(Value::Sequence(proxy_groups)) = config.get_mut("proxy-groups") {
|
||||
proxy_groups.push(Value::Mapping(proxy_chain_group));
|
||||
}
|
||||
|
||||
// 添加rules
|
||||
if let Some(Value::Sequence(rules)) = config.get_mut("rules")
|
||||
&& let Ok(rule) = serde_yaml_ng::to_value("MATCH,proxy_chain")
|
||||
{
|
||||
rules.retain(|rule| {
|
||||
rule.as_str() != Some(&format!("MATCH,{}", proxy_group_name))
|
||||
});
|
||||
rules.push(rule);
|
||||
// *rules = vec![rule];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +278,6 @@ impl IpcManager {
|
||||
let payload = serde_json::json!({
|
||||
"name": proxy
|
||||
});
|
||||
|
||||
match self.send_request("PUT", &url, Some(&payload)).await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => {
|
||||
|
||||
@@ -178,6 +178,8 @@ mod app_init {
|
||||
cmd::get_runtime_yaml,
|
||||
cmd::get_runtime_exists,
|
||||
cmd::get_runtime_logs,
|
||||
cmd::get_runtime_proxy_chain_config,
|
||||
cmd::update_proxy_chain_config_in_runtime,
|
||||
cmd::invoke_uwp_tool,
|
||||
cmd::copy_clash_env,
|
||||
cmd::get_proxies,
|
||||
|
||||
Reference in New Issue
Block a user