feat: support builtin script for enhanced mode

This commit is contained in:
GyDi 2022-11-21 21:05:00 +08:00
parent 525e5f88ae
commit bd0e932910
No known key found for this signature in database
GPG Key ID: 9C3AD40F1F99880A
7 changed files with 130 additions and 100 deletions

View File

@ -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),

View File

@ -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<ChainItem> {
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),
}

View File

@ -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<Mapping> {
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<Mapping> {
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<PrfActivate> {
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::<Vec<ChainItem>>(),
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<ChainItem>,
pub valid: Vec<String>,
}

View File

@ -65,6 +65,9 @@ pub struct IVerge {
/// 默认的延迟测试连接
pub default_latency_test: Option<String>,
/// 是否使用内部的脚本支持,默认为真
pub enable_builtin_enhanced: Option<bool>,
}
#[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);
}
/// 在初始化前尝试拿到单例端口的值

View File

@ -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;
}

View File

@ -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<ChainItem> {
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<ChainItem> {
// 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]
}
}

View File

@ -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<ChainItem>,
valid: Vec<String>,
tun_mode: bool,
) -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
let mut config = profile_config;
/// Enhance mode
/// 返回最终配置、该配置包含的键、和script执行的结果
pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
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| <Option<ChainItem>>::from(item))
.collect::<Vec<ChainItem>>(),
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));