refactor: optimize enhance mode strategy

This commit is contained in:
GyDi 2022-03-28 01:07:14 +08:00
parent 0a9c81772f
commit 5a38468144
No known key found for this signature in database
GPG Key ID: 1C95E0D3467B3084
4 changed files with 120 additions and 81 deletions

@ -88,7 +88,7 @@ pub async fn update_profile(
// reactivate the profile
if Some(index) == profiles.get_current() {
let clash = clash_state.0.lock().unwrap();
wrap_err!(clash.activate(&profiles, false))?;
wrap_err!(clash.activate_enhanced(&profiles, false, false))?;
}
Ok(())
@ -105,7 +105,7 @@ pub fn select_profile(
wrap_err!(profiles.put_current(index))?;
let clash = clash_state.0.lock().unwrap();
wrap_err!(clash.activate(&profiles, false))
wrap_err!(clash.activate_enhanced(&profiles, false, false))
}
/// change the profile chain
@ -122,7 +122,7 @@ pub fn change_profile_chain(
profiles.put_chain(chain);
clash.set_window(app_handle.get_window("main"));
wrap_err!(clash.activate_enhanced(&profiles, false))
wrap_err!(clash.activate_enhanced(&profiles, false, false))
}
/// manually exec enhanced profile
@ -137,7 +137,7 @@ pub fn enhance_profiles(
clash.set_window(app_handle.get_window("main"));
wrap_err!(clash.activate_enhanced(&profiles, false))
wrap_err!(clash.activate_enhanced(&profiles, false, false))
}
/// delete profile item
@ -151,7 +151,7 @@ pub fn delete_profile(
if wrap_err!(profiles.delete_item(index))? {
let clash = clash_state.0.lock().unwrap();
wrap_err!(clash.activate(&profiles, false))?;
wrap_err!(clash.activate_enhanced(&profiles, false, false))?;
}
Ok(())
@ -324,7 +324,7 @@ pub fn patch_verge_config(
wrap_err!(clash.tun_mode(tun_mode.unwrap()))?;
clash.update_config();
wrap_err!(clash.activate(&profiles, false))?;
wrap_err!(clash.activate_enhanced(&profiles, false, false))?;
}
let mut verge = verge_state.0.lock().unwrap();

@ -1,4 +1,5 @@
use super::{PrfEnhancedResult, Profiles, Verge};
use crate::log_if_err;
use crate::utils::{config, dirs, help};
use anyhow::{bail, Result};
use reqwest::header::HeaderMap;
@ -176,7 +177,8 @@ impl Clash {
self.update_config();
self.drop_sidecar()?;
self.run_sidecar()?;
self.activate(profiles, false)
self.activate(profiles)?;
self.activate_enhanced(profiles, false, true)
}
/// update the clash info
@ -221,7 +223,7 @@ impl Clash {
}
/// enable tun mode
/// only revise the config and restart the
/// only revise the config
pub fn tun_mode(&mut self, enable: bool) -> Result<()> {
// Windows 需要wintun.dll文件
#[cfg(target_os = "windows")]
@ -354,62 +356,57 @@ impl Clash {
}
/// enhanced profiles mode
/// only change the enhanced profiles
pub fn activate_enhanced(&self, profiles: &Profiles, delay: bool) -> Result<()> {
/// - (sync) refresh config if enhance chain is null
/// - (async) enhanced config
pub fn activate_enhanced(&self, profiles: &Profiles, delay: bool, skip: bool) -> Result<()> {
if self.window.is_none() {
bail!("failed to get the main window");
}
let win = self.window.clone().unwrap();
let event_name = help::get_uid("e");
let event_name = format!("enhanced-cb-{event_name}");
let info = self.info.clone();
let mut config = self.config.clone();
// generate the payload
let payload = profiles.gen_enhanced(event_name.clone())?;
let window = self.window.clone();
win.once(&event_name, move |event| {
let info = self.info.clone();
// do not run enhanced
if payload.chain.len() == 0 {
if skip {
return Ok(());
}
let mut config = self.config.clone();
let filter_data = Clash::strict_filter(payload.current);
for (key, value) in filter_data.into_iter() {
config.insert(key, value);
}
return Clash::_activate(info, config, self.window.clone());
}
let window = self.window.clone().unwrap();
let window_move = self.window.clone();
window.once(&event_name, move |event| {
if let Some(result) = event.payload() {
let result: PrfEnhancedResult = serde_json::from_str(result).unwrap();
if let Some(data) = result.data {
// all of these can not be revised by script
// http/https/socks port should be under control
let not_allow = vec![
"port",
"socks-port",
"mixed-port",
"allow-lan",
"mode",
"external-controller",
"secret",
"log-level",
];
let mut config = Clash::read_config();
let filter_data = Clash::loose_filter(data); // loose filter
for (key, value) in data.into_iter() {
key.as_str().map(|key_str| {
// change to lowercase
let mut key_str = String::from(key_str);
key_str.make_ascii_lowercase();
// filter
if !not_allow.contains(&&*key_str) {
config.insert(Value::String(key_str), value);
}
});
for (key, value) in filter_data.into_iter() {
config.insert(key, value);
}
log_if_err!(Clash::_activate(info, config, window_move));
log::info!("profile enhanced status {}", result.status);
Self::_activate(info, config, window).unwrap();
}
if let Some(error) = result.error {
log::error!("{error}");
}
result.error.map(|err| log::error!("{err}"));
}
});
@ -418,7 +415,7 @@ impl Clash {
if delay {
sleep(Duration::from_secs(2)).await;
}
win.emit("script-handler", payload).unwrap();
window.emit("script-handler", payload).unwrap();
});
Ok(())
@ -426,17 +423,83 @@ impl Clash {
/// activate the profile
/// auto activate enhanced profile
pub fn activate(&self, profiles: &Profiles, delay: bool) -> Result<()> {
let gen_map = profiles.gen_activate()?;
pub fn activate(&self, profiles: &Profiles) -> Result<()> {
let data = profiles.gen_activate()?;
let data = Clash::strict_filter(data);
let info = self.info.clone();
let mut config = self.config.clone();
for (key, value) in gen_map.into_iter() {
for (key, value) in data.into_iter() {
config.insert(key, value);
}
Self::_activate(info, config, self.window.clone())?;
self.activate_enhanced(profiles, delay)
Clash::_activate(info, config, self.window.clone())
}
/// only 5 default fields available (clash config fields)
/// convert to lowercase
fn strict_filter(config: Mapping) -> Mapping {
// Only the following fields are allowed:
// proxies/proxy-providers/proxy-groups/rule-providers/rules
let valid_keys = vec![
"proxies",
"proxy-providers",
"proxy-groups",
"rules",
"rule-providers",
];
let mut new_config = Mapping::new();
for (key, value) in config.into_iter() {
key.as_str().map(|key_str| {
// change to lowercase
let mut key_str = String::from(key_str);
key_str.make_ascii_lowercase();
// filter
if valid_keys.contains(&&*key_str) {
new_config.insert(Value::String(key_str), value);
}
});
}
new_config
}
/// more clash config fields available
/// convert to lowercase
fn loose_filter(config: Mapping) -> Mapping {
// all of these can not be revised by script or merge
// http/https/socks port should be under control
let not_allow = vec![
"port",
"socks-port",
"mixed-port",
"allow-lan",
"mode",
"external-controller",
"secret",
"log-level",
];
let mut new_config = Mapping::new();
for (key, value) in config.into_iter() {
key.as_str().map(|key_str| {
// change to lowercase
let mut key_str = String::from(key_str);
key_str.make_ascii_lowercase();
// filter
if !not_allow.contains(&&*key_str) {
new_config.insert(Value::String(key_str), value);
}
});
}
new_config
}
}

@ -1,7 +1,7 @@
use crate::utils::{config, dirs, help, tmpl};
use anyhow::{bail, Context, Result};
use serde::{Deserialize, Serialize};
use serde_yaml::{Mapping, Value};
use serde_yaml::Mapping;
use std::{fs, io::Write};
#[derive(Debug, Clone, Deserialize, Serialize)]
@ -575,32 +575,7 @@ impl Profiles {
bail!("failed to read the file \"{}\"", file_path.display());
}
let mut new_config = Mapping::new();
let def_config = config::read_yaml::<Mapping>(file_path.clone());
// Only the following fields are allowed:
// proxies/proxy-providers/proxy-groups/rule-providers/rules
let valid_keys = vec![
"proxies",
"proxy-providers",
"proxy-groups",
"rule-providers",
"rules",
];
for (key, value) in def_config.into_iter() {
key.as_str().map(|key_str| {
// change to lowercase
let mut key_str = String::from(key_str);
key_str.make_ascii_lowercase();
if valid_keys.contains(&&*key_str) {
new_config.insert(Value::String(key_str), value);
}
});
}
return Ok(new_config);
return Ok(config::read_yaml::<Mapping>(file_path.clone()));
}
}
@ -634,11 +609,11 @@ impl Profiles {
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct PrfEnhanced {
current: Mapping,
pub current: Mapping,
chain: Vec<PrfData>,
pub chain: Vec<PrfData>,
callback: String,
pub callback: String,
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]

@ -24,7 +24,8 @@ pub fn resolve_setup(app: &App) {
*profiles = Profiles::read_file();
clash.set_window(app.get_window("main"));
log_if_err!(clash.activate(&profiles, true));
log_if_err!(clash.activate(&profiles));
log_if_err!(clash.activate_enhanced(&profiles, true, true));
verge.init_sysproxy(clash.info.port.clone());
// enable tun mode