From bd0e932910283154d2e7f391723859c0438b87d4 Mon Sep 17 00:00:00 2001 From: GyDi Date: Mon, 21 Nov 2022 21:05:00 +0800 Subject: [PATCH] feat: support builtin script for enhanced mode --- src-tauri/src/config/config.rs | 10 +--- src-tauri/src/config/prfitem.rs | 36 -------------- src-tauri/src/config/profiles.rs | 60 ++++++------------------ src-tauri/src/config/verge.rs | 5 ++ src-tauri/src/enhance/builtin/hy_alpn.js | 10 ++++ src-tauri/src/enhance/chain.rs | 56 ++++++++++++++++++++++ src-tauri/src/enhance/mod.rs | 53 +++++++++++++++++---- 7 files changed, 130 insertions(+), 100 deletions(-) create mode 100644 src-tauri/src/enhance/builtin/hy_alpn.js create mode 100644 src-tauri/src/enhance/chain.rs diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs index 1ba7a1e..e5af8e5 100644 --- a/src-tauri/src/config/config.rs +++ b/src-tauri/src/config/config.rs @@ -84,15 +84,7 @@ impl Config { /// 生成配置存好 pub fn generate() -> Result<()> { - let clash_config = { Config::clash().latest().clone() }; - - let tun_mode = { Config::verge().latest().enable_tun_mode.clone() }; - let tun_mode = tun_mode.unwrap_or(false); - - let pa = { Config::profiles().latest().gen_activate()? }; - - let (config, exists_keys, logs) = - enhance::enhance_config(clash_config.0, pa.current, pa.chain, pa.valid, tun_mode); + let (config, exists_keys, logs) = enhance::enhance(); *Config::runtime().draft() = IRuntime { config: Some(config), diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index 664ad05..8bf8cce 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -369,40 +369,4 @@ impl PrfItem { let path = dirs::app_profiles_dir()?.join(file); fs::write(path, data.as_bytes()).context("failed to save the file") } - - /// get the data for enhanced mode - pub fn to_enhance(&self) -> Option { - let itype = self.itype.as_ref()?.as_str(); - let file = self.file.clone()?; - let uid = self.uid.clone().unwrap_or("".into()); - let path = dirs::app_profiles_dir().ok()?.join(file); - - if !path.exists() { - return None; - } - - match itype { - "script" => Some(ChainItem { - uid, - data: ChainType::Script(fs::read_to_string(path).ok()?), - }), - "merge" => Some(ChainItem { - uid, - data: ChainType::Merge(help::read_merge_mapping(&path).ok()?), - }), - _ => None, - } - } -} - -#[derive(Debug, Clone)] -pub struct ChainItem { - pub uid: String, - pub data: ChainType, -} - -#[derive(Debug, Clone)] -pub enum ChainType { - Merge(Mapping), - Script(String), } diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index f6a6399..47dfb43 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -1,4 +1,4 @@ -use super::{prfitem::PrfItem, ChainItem}; +use super::prfitem::PrfItem; use crate::utils::{dirs, help}; use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; @@ -261,52 +261,20 @@ impl IProfiles { Ok(current == uid) } - /// generate the current Mapping data - fn gen_current(&self) -> Result { - let config = Mapping::new(); - - if self.current.is_none() || self.items.is_none() { - return Ok(config); - } - - let current = self.current.as_ref().unwrap(); - for item in self.items.as_ref().unwrap().iter() { - if item.uid.as_ref() == Some(current) { - let file_path = match item.file.as_ref() { - Some(file) => dirs::app_profiles_dir()?.join(file), - None => bail!("failed to get the file field"), - }; - - return Ok(help::read_merge_mapping(&file_path)?); + /// 获取current指向的配置内容 + pub fn current_mapping(&self) -> Result { + match (self.current.as_ref(), self.items.as_ref()) { + (Some(current), Some(items)) => { + if let Some(item) = items.iter().find(|e| e.uid.as_ref() == Some(current)) { + let file_path = match item.file.as_ref() { + Some(file) => dirs::app_profiles_dir()?.join(file), + None => bail!("failed to get the file field"), + }; + return Ok(help::read_merge_mapping(&file_path)?); + } + bail!("failed to find the current profile \"uid:{current}\""); } + _ => Ok(Mapping::new()), } - bail!("failed to find the current profile \"uid:{current}\""); - } - - /// generate the data for activate clash config - pub fn gen_activate(&self) -> Result { - let current = self.gen_current()?; - let chain = match self.chain.as_ref() { - Some(chain) => chain - .iter() - .filter_map(|uid| self.get_item(uid).ok()) - .filter_map(|item| item.to_enhance()) - .collect::>(), - None => vec![], - }; - let valid = self.valid.clone().unwrap_or(vec![]); - - Ok(PrfActivate { - current, - chain, - valid, - }) } } - -#[derive(Default, Clone)] -pub struct PrfActivate { - pub current: Mapping, - pub chain: Vec, - pub valid: Vec, -} diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index 60143ee..43f175b 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -65,6 +65,9 @@ pub struct IVerge { /// 默认的延迟测试连接 pub default_latency_test: Option, + + /// 是否使用内部的脚本支持,默认为真 + pub enable_builtin_enhanced: Option, } #[derive(Default, Debug, Clone, Deserialize, Serialize)] @@ -107,6 +110,7 @@ impl IVerge { enable_proxy_guard: Some(false), proxy_guard_duration: Some(30), auto_close_connection: Some(true), + enable_builtin_enhanced: Some(true), ..Self::default() } } @@ -148,6 +152,7 @@ impl IVerge { patch!(auto_close_connection); patch!(default_latency_test); + patch!(enable_builtin_enhanced); } /// 在初始化前尝试拿到单例端口的值 diff --git a/src-tauri/src/enhance/builtin/hy_alpn.js b/src-tauri/src/enhance/builtin/hy_alpn.js new file mode 100644 index 0000000..da1fac0 --- /dev/null +++ b/src-tauri/src/enhance/builtin/hy_alpn.js @@ -0,0 +1,10 @@ +function main(params) { + if (Array.isArray(params.proxies)) { + params.proxies.forEach((p, i) => { + if (p.type === "hysteria" && typeof p.alpn === "string") { + params.proxies[i].alpn = [p.alpn]; + } + }); + } + return params; +} diff --git a/src-tauri/src/enhance/chain.rs b/src-tauri/src/enhance/chain.rs new file mode 100644 index 0000000..1d65ba2 --- /dev/null +++ b/src-tauri/src/enhance/chain.rs @@ -0,0 +1,56 @@ +use crate::{ + config::PrfItem, + utils::{dirs, help}, +}; +use serde_yaml::Mapping; +use std::fs; + +#[derive(Debug, Clone)] +pub struct ChainItem { + pub uid: String, + pub data: ChainType, +} + +#[derive(Debug, Clone)] +pub enum ChainType { + Merge(Mapping), + Script(String), +} + +impl From<&PrfItem> for Option { + fn from(item: &PrfItem) -> Self { + let itype = item.itype.as_ref()?.as_str(); + let file = item.file.clone()?; + let uid = item.uid.clone().unwrap_or("".into()); + let path = dirs::app_profiles_dir().ok()?.join(file); + + if !path.exists() { + return None; + } + + match itype { + "script" => Some(ChainItem { + uid, + data: ChainType::Script(fs::read_to_string(path).ok()?), + }), + "merge" => Some(ChainItem { + uid, + data: ChainType::Merge(help::read_merge_mapping(&path).ok()?), + }), + _ => None, + } + } +} + +impl ChainItem { + /// 内建支持一些脚本 + pub fn builtin() -> Vec { + // meta 1.13.2 alpn string 转 数组 + let hy_alpn = ChainItem { + uid: "verge_hy_alpn".into(), + data: ChainType::Script(include_str!("./builtin/hy_alpn.js").into()), + }; + + vec![hy_alpn] + } +} diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs index 0b00035..4cf9231 100644 --- a/src-tauri/src/enhance/mod.rs +++ b/src-tauri/src/enhance/mod.rs @@ -1,32 +1,67 @@ +mod chain; mod field; mod merge; mod script; mod tun; +use self::chain::*; pub(self) use self::field::*; use self::merge::*; use self::script::*; use self::tun::*; -use crate::config::{ChainItem, ChainType}; +use crate::config::Config; use serde_yaml::Mapping; use std::collections::HashMap; use std::collections::HashSet; type ResultLog = Vec<(String, String)>; -pub fn enhance_config( - clash_config: Mapping, - profile_config: Mapping, - chain: Vec, - valid: Vec, - tun_mode: bool, -) -> (Mapping, Vec, HashMap) { - let mut config = profile_config; +/// Enhance mode +/// 返回最终配置、该配置包含的键、和script执行的结果 +pub fn enhance() -> (Mapping, Vec, HashMap) { + let clash_config = { Config::clash().latest().0.clone() }; + + let (tun_mode, enable_builtin) = { + let verge = Config::verge(); + let verge = verge.latest(); + ( + verge.enable_tun_mode.clone(), + verge.enable_builtin_enhanced.clone(), + ) + }; + + let tun_mode = tun_mode.unwrap_or(false); + let enable_builtin = enable_builtin.unwrap_or(true); + + let (mut config, mut chain, valid) = { + let profiles = Config::profiles(); + let profiles = profiles.latest(); + + let current = profiles.current_mapping().unwrap_or(Mapping::new()); + + let chain = match profiles.chain.as_ref() { + Some(chain) => chain + .iter() + .filter_map(|uid| profiles.get_item(uid).ok()) + .filter_map(|item| >::from(item)) + .collect::>(), + None => vec![], + }; + + let valid = profiles.valid.clone().unwrap_or(vec![]); + + (current, chain, valid) + }; + let mut result_map = HashMap::new(); let mut exists_keys = use_keys(&config); let valid = use_valid_fields(valid); + if enable_builtin { + chain.extend(ChainItem::builtin().into_iter()); + } + chain.into_iter().for_each(|item| match item.data { ChainType::Merge(merge) => { exists_keys.extend(use_keys(&merge));