diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs index a00f3c9..e59b307 100644 --- a/src-tauri/src/config/clash.rs +++ b/src-tauri/src/config/clash.rs @@ -4,9 +4,37 @@ use once_cell::sync::OnceCell; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; use serde_yaml::{Mapping, Value}; -use std::sync::Arc; +use std::{net::SocketAddr, sync::Arc}; + +#[derive(Default, Debug, Clone)] +pub struct IClashTemp(pub Mapping); + +impl IClashTemp { + pub fn new() -> Self { + Self(config::read_merge_mapping(dirs::clash_path())) + } + + pub fn patch_config(&mut self, patch: Mapping) { + for (key, value) in patch.into_iter() { + self.0.insert(key, value); + } + } + + pub fn save_config(&self) -> Result<()> { + config::save_yaml( + dirs::clash_path(), + &self.0, + Some("# Default Config For ClashN Core\n\n"), + ) + } + + pub fn get_info(&self) -> Result<ClashInfoN> { + Ok(ClashInfoN::from(&self.0)) + } +} #[derive(Debug)] +#[deprecated] pub struct ClashN { /// maintain the clash config pub config: Arc<Mutex<Mapping>>, @@ -167,3 +195,71 @@ impl ClashInfoN { } } } + +#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub struct IClash { + pub mixed_port: Option<u16>, + pub allow_lan: Option<bool>, + pub log_level: Option<String>, + pub ipv6: Option<bool>, + pub mode: Option<String>, + pub external_controller: Option<String>, + pub secret: Option<String>, + pub dns: Option<IClashDNS>, + pub tun: Option<IClashTUN>, + pub interface_name: Option<String>, +} + +#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub struct IClashTUN { + pub enable: Option<bool>, + pub stack: Option<String>, + pub auto_route: Option<bool>, + pub auto_detect_interface: Option<bool>, + pub dns_hijack: Option<Vec<String>>, +} + +#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub struct IClashDNS { + pub enable: Option<bool>, + pub listen: Option<String>, + pub default_nameserver: Option<Vec<String>>, + pub enhanced_mode: Option<String>, + pub fake_ip_range: Option<String>, + pub use_hosts: Option<bool>, + pub fake_ip_filter: Option<Vec<String>>, + pub nameserver: Option<Vec<String>>, + pub fallback: Option<Vec<String>>, + pub fallback_filter: Option<IClashFallbackFilter>, + pub nameserver_policy: Option<Vec<String>>, +} + +#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub struct IClashFallbackFilter { + pub geoip: Option<bool>, + pub geoip_code: Option<String>, + pub ipcidr: Option<Vec<String>>, + pub domain: Option<Vec<String>>, +} + +#[test] +fn test() { + let socket = SocketAddr::new("127.0.0.1".parse().unwrap(), 9090); + + let s = "[::]:8080".parse::<SocketAddr>(); + + dbg!(s); + + // match "::8080".parse::<SocketAddr>() { + // Ok(_) => {} + // Err(err) => { + + // } + // } + + // assert_eq!(":8080".parse(), Ok(socket)); +} diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs index 324a62f..9ca78df 100644 --- a/src-tauri/src/config/config.rs +++ b/src-tauri/src/config/config.rs @@ -1,8 +1,12 @@ -use super::{Draft, IVerge}; +use super::{Draft, IClashTemp, IProfiles, IVerge}; +use crate::config::ClashN; use once_cell::sync::OnceCell; +use serde_yaml::Mapping; pub struct Config { + clash_config: Draft<IClashTemp>, verge_config: Draft<IVerge>, + profiles_config: Draft<IProfiles>, } impl Config { @@ -10,11 +14,33 @@ impl Config { static CONFIG: OnceCell<Config> = OnceCell::new(); CONFIG.get_or_init(|| Config { + clash_config: Draft::from(IClashTemp::new()), verge_config: Draft::from(IVerge::new()), + profiles_config: Draft::from(IProfiles::new()), }) } + // pub fn clash<'a>() -> MappedMutexGuard<'a, IClash> { + // Self::global().clash_config.latest() + // } + + // pub fn verge<'a>() -> MappedMutexGuard<'a, IVerge> { + // Self::global().verge_config.latest() + // } + + // pub fn profiles<'a>() -> MappedMutexGuard<'a, IProfiles> { + // Self::global().profiles_config.latest() + // } + + pub fn clash() -> Draft<IClashTemp> { + Self::global().clash_config.clone() + } + pub fn verge() -> Draft<IVerge> { Self::global().verge_config.clone() } + + pub fn profiles() -> Draft<IProfiles> { + Self::global().profiles_config.clone() + } } diff --git a/src-tauri/src/config/draft.rs b/src-tauri/src/config/draft.rs index 01f7bec..64bc5c8 100644 --- a/src-tauri/src/config/draft.rs +++ b/src-tauri/src/config/draft.rs @@ -1,4 +1,4 @@ -use super::{IProfiles, IVerge}; +use super::{IClash, IClashTemp, IProfiles, IVerge}; use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; use serde_yaml::Mapping; use std::sync::Arc; @@ -15,6 +15,16 @@ macro_rules! draft_define { MutexGuard::map(self.inner.lock(), |guard| &mut guard.0) } + pub fn latest(&self) -> MappedMutexGuard<$id> { + MutexGuard::map(self.inner.lock(), |inner| { + if inner.1.is_none() { + &mut inner.0 + } else { + inner.1.as_mut().unwrap() + } + }) + } + pub fn draft(&self) -> MappedMutexGuard<$id> { MutexGuard::map(self.inner.lock(), |mut inner| { if inner.1.is_none() { @@ -54,6 +64,8 @@ macro_rules! draft_define { }; } +draft_define!(IClash); +draft_define!(IClashTemp); draft_define!(IVerge); draft_define!(Mapping); draft_define!(IProfiles); @@ -85,6 +97,9 @@ fn test_draft() { assert_eq!(draft.draft().enable_auto_launch, Some(false)); assert_eq!(draft.draft().enable_tun_mode, Some(true)); + assert_eq!(draft.latest().enable_auto_launch, Some(false)); + assert_eq!(draft.latest().enable_tun_mode, Some(true)); + assert!(draft.apply().is_some()); assert!(draft.apply().is_none()); diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index ad50f63..3779c51 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -12,6 +12,7 @@ use std::collections::HashMap; use std::sync::Arc; use std::{fs, io::Write}; +#[deprecated] pub struct ProfilesN { pub config: Arc<Mutex<IProfiles>>, } @@ -87,6 +88,10 @@ macro_rules! patch { } impl IProfiles { + pub fn new() -> Self { + Self::read_file() + } + /// read the config from the file pub fn read_file() -> Self { let mut profiles = config::read_yaml::<Self>(dirs::profiles_path()); diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index 9a2bc45..7df68f9 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -5,6 +5,7 @@ use parking_lot::Mutex; use serde::{Deserialize, Serialize}; use std::sync::Arc; +#[deprecated] pub struct VergeN { pub config: Arc<Mutex<IVerge>>, } @@ -51,8 +52,7 @@ impl VergeN { /// ### `verge.yaml` schema #[derive(Default, Debug, Clone, Deserialize, Serialize)] pub struct IVerge { - /// app listening port - /// for app singleton + /// app listening port for app singleton pub app_singleton_port: Option<u16>, // i18n diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index 4c587aa..30fe6cc 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -1,7 +1,7 @@ use super::{clash_api, logger::Logger}; use crate::{ config::*, - enhance, + enhance, log_err, utils::{self, dirs}, }; use anyhow::{bail, Context, Result}; @@ -14,8 +14,6 @@ use tokio::time::sleep; #[derive(Debug)] pub struct CoreManager { - clash_core: Arc<Mutex<String>>, - sidecar: Arc<Mutex<Option<CommandChild>>>, #[allow(unused)] @@ -29,7 +27,6 @@ impl CoreManager { static CORE_MANAGER: OnceCell<CoreManager> = OnceCell::new(); CORE_MANAGER.get_or_init(|| CoreManager { - clash_core: Arc::new(Mutex::new("clash".into())), sidecar: Arc::new(Mutex::new(None)), runtime_config: Arc::new(Mutex::new(RuntimeResult::default())), use_service_mode: Arc::new(Mutex::new(false)), @@ -50,14 +47,14 @@ impl CoreManager { } } - // 使用配置的核心 - let verge = VergeN::global().config.lock(); - if let Some(verge_core) = verge.clash_core.as_ref() { - if verge_core == "clash" || verge_core == "clash-meta" { - let mut clash_core = self.clash_core.lock(); - *clash_core = verge_core.clone(); - } - } + // // 使用配置的核心 + // let verge_core = { Config::verge().clash_core.clone() }; + // if let Some(verge_core) = verge_core { + // if verge_core == "clash" || verge_core == "clash-meta" { + // let mut clash_core = self.clash_core.lock(); + // *clash_core = verge_core; + // } + // } // 启动clash self.run_core()?; @@ -76,7 +73,8 @@ impl CoreManager { let config_path = dirs::clash_runtime_yaml(); let config_path = dirs::path_to_str(&config_path)?; - let clash_core = { self.clash_core.lock().clone() }; + let clash_core = { Config::verge().latest().clash_core.clone() }; + let clash_core = clash_core.unwrap_or("clash".into()); let output = Command::new_sidecar(clash_core)? .args(["-t", "-f", config_path]) @@ -104,7 +102,8 @@ impl CoreManager { let app_dir = dirs::app_home_dir(); let app_dir = dirs::path_to_str(&app_dir)?; - let clash_core = { self.clash_core.lock().clone() }; + let clash_core = { Config::verge().latest().clash_core.clone() }; + let clash_core = clash_core.unwrap_or("clash".into()); // fix #212 let args = match clash_core.as_str() { @@ -177,30 +176,23 @@ impl CoreManager { // 清掉旧日志 Logger::global().clear_log(); - let old_core = { - let mut self_core = self.clash_core.lock(); - let old_core = self_core.to_owned(); // 保存一下旧值 - *self_core = clash_core.clone(); - old_core - }; + { + Config::verge().draft().clash_core = Some(clash_core); + } match self.run_core() { Ok(_) => { - // 更新到配置文件 - { - VergeN::global().config.lock().clash_core = Some(clash_core); - } - - let _ = VergeN::global().save_file(); + log_err!({ + Config::verge().apply(); + Config::verge().latest().save_file() + }); sleep(Duration::from_millis(100)).await; // 等一会儿再更新配置 self.activate_config().await?; Ok(()) } Err(err) => { - // 恢复旧的值 - let mut self_core = self.clash_core.lock(); - *self_core = old_core; + Config::verge().discard(); Err(err) } } @@ -215,15 +207,15 @@ impl CoreManager { /// 激活一个配置 pub async fn activate_config(&self) -> Result<()> { - let clash_config = { ClashN::global().config.lock().clone() }; + let clash_config = { Config::clash().latest().clone() }; - let tun_mode = { VergeN::global().config.lock().enable_tun_mode.clone() }; + let tun_mode = { Config::verge().latest().enable_tun_mode.clone() }; let tun_mode = tun_mode.unwrap_or(false); - let pa = { ProfilesN::global().config.lock().gen_activate()? }; + let pa = { Config::profiles().latest().gen_activate()? }; let (config, exists_keys, logs) = - enhance::enhance_config(clash_config, pa.current, pa.chain, pa.valid, tun_mode); + enhance::enhance_config(clash_config.0, pa.current, pa.chain, pa.valid, tun_mode); // 保存到文件中 let runtime_path = dirs::clash_runtime_yaml(); diff --git a/src-tauri/src/core/hotkey.rs b/src-tauri/src/core/hotkey.rs index 48c4482..cd844db 100644 --- a/src-tauri/src/core/hotkey.rs +++ b/src-tauri/src/core/hotkey.rs @@ -1,4 +1,4 @@ -use crate::{config, feat, log_err}; +use crate::{config::Config, feat, log_err}; use anyhow::{bail, Result}; use once_cell::sync::OnceCell; use parking_lot::Mutex; @@ -24,9 +24,9 @@ impl Hotkey { pub fn init(&self, app_handle: AppHandle) -> Result<()> { *self.app_handle.lock() = Some(app_handle); - let verge = config::VergeN::global().config.lock(); + let verge = Config::verge(); - if let Some(hotkeys) = verge.hotkeys.as_ref() { + if let Some(hotkeys) = verge.latest().hotkeys.as_ref() { for hotkey in hotkeys.iter() { let mut iter = hotkey.split(','); let func = iter.next(); diff --git a/src-tauri/src/core/sysopt.rs b/src-tauri/src/core/sysopt.rs index 7850474..f9231e0 100644 --- a/src-tauri/src/core/sysopt.rs +++ b/src-tauri/src/core/sysopt.rs @@ -1,4 +1,4 @@ -use crate::{config, log_err}; +use crate::{config::Config, log_err}; use anyhow::{anyhow, bail, Result}; use auto_launch::{AutoLaunch, AutoLaunchBuilder}; use once_cell::sync::OnceCell; @@ -43,7 +43,7 @@ impl Sysopt { /// init the sysproxy pub fn init_sysproxy(&self) -> Result<()> { - let port = { config::ClashN::global().info.lock().port.clone() }; + let port = { Config::clash().latest().get_info()?.port }; if port.is_none() { bail!("clash port is none"); @@ -51,16 +51,20 @@ impl Sysopt { let port = port.unwrap().parse::<u16>()?; - let verge = config::VergeN::global().config.lock(); - let enable = verge.enable_system_proxy.clone().unwrap_or(false); - let bypass = verge.system_proxy_bypass.clone(); - let bypass = bypass.unwrap_or(DEFAULT_BYPASS.into()); + let (enable, bypass) = { + let verge = Config::verge(); + let verge = verge.latest(); + ( + verge.enable_system_proxy.clone().unwrap_or(false), + verge.system_proxy_bypass.clone(), + ) + }; let current = Sysproxy { enable, host: String::from("127.0.0.1"), port, - bypass, + bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()), }; if enable { @@ -87,16 +91,18 @@ impl Sysopt { return self.init_sysproxy(); } - let verge = config::VergeN::global().config.lock(); - - let enable = verge.enable_system_proxy.clone().unwrap_or(false); - let bypass = verge.system_proxy_bypass.clone(); - let bypass = bypass.unwrap_or(DEFAULT_BYPASS.into()); - + let (enable, bypass) = { + let verge = Config::verge(); + let verge = verge.latest(); + ( + verge.enable_system_proxy.clone().unwrap_or(false), + verge.system_proxy_bypass.clone(), + ) + }; let mut sysproxy = cur_sysproxy.take().unwrap(); sysproxy.enable = enable; - sysproxy.bypass = bypass; + sysproxy.bypass = bypass.unwrap_or(DEFAULT_BYPASS.into()); sysproxy.set_system_proxy()?; *cur_sysproxy = Some(sysproxy); @@ -138,8 +144,13 @@ impl Sysopt { /// init the auto launch pub fn init_launch(&self) -> Result<()> { - let verge = config::VergeN::global().config.lock(); - let enable = verge.enable_auto_launch.clone().unwrap_or(false); + let enable = { + Config::verge() + .latest() + .enable_auto_launch + .clone() + .unwrap_or(false) + }; let app_exe = current_exe()?; let app_exe = dunce::canonicalize(app_exe)?; @@ -202,10 +213,13 @@ impl Sysopt { drop(auto_launch); return self.init_launch(); } - - let verge = config::VergeN::global().config.lock(); - let enable = verge.enable_auto_launch.clone().unwrap_or(false); - + let enable = { + Config::verge() + .latest() + .enable_auto_launch + .clone() + .unwrap_or(false) + }; let auto_launch = auto_launch.as_ref().unwrap(); match enable { @@ -238,13 +252,16 @@ impl Sysopt { loop { sleep(Duration::from_secs(wait_secs)).await; - let verge = config::VergeN::global().config.lock(); - - let enable = verge.enable_system_proxy.clone().unwrap_or(false); - let guard = verge.enable_proxy_guard.clone().unwrap_or(false); - let guard_duration = verge.proxy_guard_duration.clone().unwrap_or(10); - let bypass = verge.system_proxy_bypass.clone(); - drop(verge); + let (enable, guard, guard_duration, bypass) = { + let verge = Config::verge(); + let verge = verge.latest(); + ( + verge.enable_system_proxy.clone().unwrap_or(false), + verge.enable_proxy_guard.clone().unwrap_or(false), + verge.proxy_guard_duration.clone().unwrap_or(10), + verge.system_proxy_bypass.clone(), + ) + }; // stop loop if !enable || !guard { @@ -256,20 +273,21 @@ impl Sysopt { log::debug!(target: "app", "try to guard the system proxy"); - let port = { config::ClashN::global().info.lock().port.clone() }; - match port.unwrap_or("".into()).parse::<u16>() { - Ok(port) => { - let sysproxy = Sysproxy { - enable: true, - host: "127.0.0.1".into(), - port, - bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()), - }; + if let Ok(info) = { Config::clash().latest().get_info() } { + match info.port.unwrap_or("".into()).parse::<u16>() { + Ok(port) => { + let sysproxy = Sysproxy { + enable: true, + host: "127.0.0.1".into(), + port, + bypass: bypass.unwrap_or(DEFAULT_BYPASS.into()), + }; - log_err!(sysproxy.set_system_proxy()); - } - Err(_) => { - log::error!(target: "app", "failed to parse clash port in guard proxy") + log_err!(sysproxy.set_system_proxy()); + } + Err(_) => { + log::error!(target: "app", "failed to parse clash port in guard proxy") + } } } } diff --git a/src-tauri/src/core/tray.rs b/src-tauri/src/core/tray.rs index 5a12f07..36fa652 100644 --- a/src-tauri/src/core/tray.rs +++ b/src-tauri/src/core/tray.rs @@ -1,5 +1,5 @@ use crate::log_err; -use crate::{config, feat, utils::resolve}; +use crate::{config::Config, feat, utils::resolve}; use anyhow::Result; use tauri::{ api, AppHandle, CustomMenuItem, Manager, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, @@ -10,10 +10,7 @@ pub struct Tray {} impl Tray { pub fn tray_menu(app_handle: &AppHandle) -> SystemTrayMenu { - let zh = { - let verge = config::VergeN::global().config.lock(); - verge.language == Some("zh".into()) - }; + let zh = { Config::verge().latest().language == Some("zh".into()) }; let version = app_handle.package_info().version.to_string(); @@ -76,8 +73,9 @@ impl Tray { pub fn update_part(app_handle: &AppHandle) -> Result<()> { let mode = { - let clash = config::ClashN::global().config.lock(); - clash + Config::clash() + .latest() + .0 .get("mode") .map(|val| val.as_str().unwrap_or("rule")) .unwrap_or("rule") @@ -91,7 +89,8 @@ impl Tray { let _ = tray.get_item("direct_mode").set_selected(mode == "direct"); let _ = tray.get_item("script_mode").set_selected(mode == "script"); - let verge = config::VergeN::global().config.lock(); + let verge = Config::verge(); + let verge = verge.latest(); let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false); let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false); diff --git a/src-tauri/src/feat.rs b/src-tauri/src/feat.rs index 39d6d98..d94fe7d 100644 --- a/src-tauri/src/feat.rs +++ b/src-tauri/src/feat.rs @@ -212,3 +212,9 @@ pub async fn handle_activate() -> Result<()> { } } } + +/// 更新某个profile +/// 如果更新当前配置就激活配置 +pub async fn update_profile(uid: String, option: Option<PrfOption>) -> Result<()> { + Ok(()) +} diff --git a/src-tauri/src/utils/tmpl.rs b/src-tauri/src/utils/tmpl.rs index dc311f6..8d20a2e 100644 --- a/src-tauri/src/utils/tmpl.rs +++ b/src-tauri/src/utils/tmpl.rs @@ -19,7 +19,7 @@ items: ~ "; /// template for `verge.yaml` -pub const VERGE_CONFIG: &[u8] = b"# Defaulf Config For Clash Verge +pub const VERGE_CONFIG: &[u8] = b"# Default Config For Clash Verge language: en theme_mode: light