diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index 01cf870..7ad2f4b 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -260,7 +260,7 @@ pub fn get_verge_config(verge_state: State<'_, VergeState>) -> Result, ) -> Result<(), String> { diff --git a/src-tauri/src/core/verge.rs b/src-tauri/src/core/verge.rs index b3ed0d9..74632f5 100644 --- a/src-tauri/src/core/verge.rs +++ b/src-tauri/src/core/verge.rs @@ -1,7 +1,11 @@ -use crate::utils::{config, dirs, sysopt::SysProxyConfig}; +use crate::{ + core::Clash, + utils::{config, dirs, sysopt::SysProxyConfig}, +}; use auto_launch::{AutoLaunch, AutoLaunchBuilder}; use serde::{Deserialize, Serialize}; -use tauri::api::path::resource_dir; +use std::sync::Arc; +use tauri::{api::path::resource_dir, async_runtime::Mutex}; /// ### `verge.yaml` schema #[derive(Default, Debug, Clone, Deserialize, Serialize)] @@ -22,6 +26,9 @@ pub struct VergeConfig { /// set system proxy pub enable_system_proxy: Option, + /// enable proxy guard + pub enable_proxy_guard: Option, + /// set system proxy bypass pub system_proxy_bypass: Option, } @@ -53,6 +60,9 @@ pub struct Verge { pub cur_sysproxy: Option, pub auto_launch: Option, + + /// record whether the guard async is running or not + guard_state: Arc>, } impl Default for Verge { @@ -68,6 +78,7 @@ impl Verge { old_sysproxy: None, cur_sysproxy: None, auto_launch: None, + guard_state: Arc::new(Mutex::new(false)), } } @@ -92,6 +103,9 @@ impl Verge { self.cur_sysproxy = Some(sysproxy); } + + // launchs the system proxy guard + Verge::guard_proxy(10, self.guard_state.clone()); } /// reset the sysproxy @@ -154,10 +168,9 @@ impl Verge { let auto_launch = self.auto_launch.clone().unwrap(); - let result = if enable { - auto_launch.enable() - } else { - auto_launch.disable() + let result = match enable { + true => auto_launch.enable(), + false => auto_launch.disable(), }; match result { @@ -169,24 +182,6 @@ impl Verge { } } - // fn guard_thread(&mut self) -> Result<(), String> { - // let sysproxy = self.cur_sysproxy.clone(); - - // use std::{thread, time}; - // tauri::async_runtime::spawn(async move { - // if let Some(sysproxy) = sysproxy { - // sysproxy.set_sys(); - // } - - // let ten_millis = time::Duration::from_millis(10); - // let now = time::Instant::now(); - - // thread::sleep(ten_millis); - // }); - - // Ok(()) - // } - /// patch verge config /// There should be only one update at a time here /// so call the save_file at the end is savely @@ -248,10 +243,75 @@ impl Verge { self.config.system_proxy_bypass = Some(bypass); } + // proxy guard + // only change it + if patch.enable_proxy_guard.is_some() { + self.config.enable_proxy_guard = patch.enable_proxy_guard; + } + + // relaunch the guard + if patch.enable_system_proxy.is_some() || patch.enable_proxy_guard.is_some() { + Verge::guard_proxy(10, self.guard_state.clone()); + } + self.config.save_file() } } +impl Verge { + /// launch a system proxy guard + /// read config from file directly + pub fn guard_proxy(wait_secs: u64, guard_state: Arc>) { + use tokio::time::{sleep, Duration}; + + tauri::async_runtime::spawn(async move { + // if it is running, exit + let mut state = guard_state.lock().await; + if *state { + return; + } + *state = true; + std::mem::drop(state); + + loop { + sleep(Duration::from_secs(wait_secs)).await; + + log::debug!("[Guard]: heartbeat detection"); + + let verge = Verge::new(); + + let enable_proxy = verge.config.enable_system_proxy.unwrap_or(false); + let enable_guard = verge.config.enable_proxy_guard.unwrap_or(false); + + // stop loop + if !enable_guard || !enable_proxy { + break; + } + + log::info!("[Guard]: try to guard proxy"); + + let clash = Clash::new(); + + match &clash.info.port { + Some(port) => { + let bypass = verge.config.system_proxy_bypass.clone(); + let sysproxy = SysProxyConfig::new(true, port.clone(), bypass); + + if let Err(err) = sysproxy.set_sys() { + log::error!("[Guard]: {err}"); + log::error!("[Guard]: fail to set system proxy"); + } + } + None => log::error!("[Guard]: fail to parse clash port"), + } + } + + let mut state = guard_state.lock().await; + *state = false; + }); + } +} + // Get the target app_path fn get_app_path(app_name: &str) -> String { #[cfg(target_os = "linux")] diff --git a/src/components/setting/setting-system.tsx b/src/components/setting/setting-system.tsx index b19e986..c38055c 100644 --- a/src/components/setting/setting-system.tsx +++ b/src/components/setting/setting-system.tsx @@ -15,9 +15,10 @@ const SettingSystem = ({ onError }: Props) => { const { data: vergeConfig } = useSWR("getVergeConfig", getVergeConfig); const { - enable_auto_launch: startup = false, - enable_system_proxy: proxy = false, - system_proxy_bypass: bypass = "", + enable_auto_launch = false, + enable_system_proxy = false, + system_proxy_bypass = "", + enable_proxy_guard = false, } = vergeConfig ?? {}; const onSwitchFormat = (_e: any, value: boolean) => value; @@ -30,7 +31,7 @@ const SettingSystem = ({ onError }: Props) => { { } /> { - {proxy && ( + {enable_system_proxy && ( + + + onChangeData({ enable_proxy_guard: e })} + onGuard={(e) => patchVergeConfig({ enable_proxy_guard: e })} + > + + + + )} + + {enable_system_proxy && ( e.target.value} onChange={(e) => onChangeData({ system_proxy_bypass: e })} diff --git a/src/services/types.ts b/src/services/types.ts index 10d9381..80eb099 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -115,6 +115,7 @@ export namespace CmdType { traffic_graph?: boolean; enable_auto_launch?: boolean; enable_system_proxy?: boolean; + enable_proxy_guard?: boolean; system_proxy_bypass?: string; } }