diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index 8b2a6b5793d1712814220fdbd2104f71f8a4e5fc..2a7c87c8b3fd3ea1bf941a6d0eed71289c48a3a4 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -259,10 +259,26 @@ pub fn get_verge_config(verge_state: State<'_, VergeState>) -> Result<VergeConfi #[tauri::command] pub fn patch_verge_config( payload: VergeConfig, + clash_state: State<'_, ClashState>, verge_state: State<'_, VergeState>, + profiles_state: State<'_, ProfilesState>, ) -> Result<(), String> { + let tun_mode = payload.enable_tun_mode.clone(); + let mut verge = verge_state.0.lock().unwrap(); - verge.patch_config(payload) + verge.patch_config(payload)?; + + // change tun mode + if tun_mode.is_some() { + let mut clash = clash_state.0.lock().unwrap(); + let profiles = profiles_state.0.lock().unwrap(); + + clash.tun_mode(tun_mode.unwrap())?; + clash.update_config(); + profiles.activate(&clash)?; + } + + Ok(()) } /// kill all sidecars when update app diff --git a/src-tauri/src/core/clash.rs b/src-tauri/src/core/clash.rs index c7a23a977ca26bcc75d5bcfdbcc6230efd3d8ba4..80ea316cbc18e2b6e6724f13b3d53311a00aec8c 100644 --- a/src-tauri/src/core/clash.rs +++ b/src-tauri/src/core/clash.rs @@ -203,6 +203,48 @@ impl Clash { } self.save_config() } + + /// enable tun mode + /// only revise the config and restart the + pub fn tun_mode(&mut self, enable: bool) -> Result<(), String> { + let tun_key = Value::String("tun".into()); + let tun_val = self.config.get(&tun_key); + + let mut new_val = Mapping::new(); + + if tun_val.is_some() && tun_val.as_ref().unwrap().is_mapping() { + new_val = tun_val.as_ref().unwrap().as_mapping().unwrap().clone(); + } + + macro_rules! revise { + ($map: expr, $key: expr, $val: expr) => { + let ret_key = Value::String($key.into()); + if $map.contains_key(&ret_key) { + $map[&ret_key] = $val; + } else { + $map.insert(ret_key, $val); + } + }; + } + + macro_rules! append { + ($map: expr, $key: expr, $val: expr) => { + let ret_key = Value::String($key.into()); + if !$map.contains_key(&ret_key) { + $map.insert(ret_key, $val); + } + }; + } + + revise!(new_val, "enable", Value::from(enable)); + append!(new_val, "stack", Value::from("gvisor")); + append!(new_val, "auto-route", Value::from(true)); + append!(new_val, "auto-detect-interface", Value::from(true)); + + revise!(self.config, "tun", Value::from(new_val)); + + self.save_config() + } } impl Default for Clash { diff --git a/src-tauri/src/core/verge.rs b/src-tauri/src/core/verge.rs index c6959fb11d800862cae1e167e2c28c452b51b554..349480ab1327360d6a68ad3a0dbe32f43b763de4 100644 --- a/src-tauri/src/core/verge.rs +++ b/src-tauri/src/core/verge.rs @@ -20,6 +20,9 @@ pub struct VergeConfig { /// enable traffic graph default is true pub traffic_graph: Option<bool>, + /// clash tun mode + pub enable_tun_mode: Option<bool>, + /// can the app auto startup pub enable_auto_launch: Option<bool>, @@ -258,6 +261,11 @@ impl Verge { Verge::guard_proxy(self.guard_state.clone()); } + // handle the tun mode + if patch.enable_tun_mode.is_some() { + self.config.enable_tun_mode = patch.enable_tun_mode; + } + self.config.save_file() } } diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs index bb1cc6aea385d542815f496a11fa03e021b6179a..9fe90ce0726b83af3016ef50bae04c10632af55e 100644 --- a/src-tauri/src/utils/resolve.rs +++ b/src-tauri/src/utils/resolve.rs @@ -22,18 +22,27 @@ pub fn resolve_setup(app: &App) { let mut profiles = profiles_state.0.lock().unwrap(); if let Err(err) = clash.run_sidecar() { - log::error!("{}", err); + log::error!("{err}"); } *profiles = Profiles::read_file(); if let Err(err) = profiles.activate(&clash) { - log::error!("{}", err); + log::error!("{err}"); } verge.init_sysproxy(clash.info.port.clone()); + // enable tun mode + if verge.config.enable_tun_mode.clone().unwrap_or(false) + && verge.cur_sysproxy.is_some() + && verge.cur_sysproxy.as_ref().unwrap().enable + { + log::info!("enable tun mode"); + clash.tun_mode(true).unwrap(); + } + verge.init_launch(); if let Err(err) = verge.sync_launch() { - log::error!("{}", err); + log::error!("{err}"); } } diff --git a/src/components/setting/setting-system.tsx b/src/components/setting/setting-system.tsx index d7db114822fd9955bdbd4328dcd8a2946d217635..dfc482ec4b5d2f1bfbbb8f933c0f4417b76381ea 100644 --- a/src/components/setting/setting-system.tsx +++ b/src/components/setting/setting-system.tsx @@ -15,6 +15,7 @@ const SettingSystem = ({ onError }: Props) => { const { data: vergeConfig } = useSWR("getVergeConfig", getVergeConfig); const { + enable_tun_mode = false, enable_auto_launch = false, enable_system_proxy = false, system_proxy_bypass = "", @@ -28,6 +29,20 @@ const SettingSystem = ({ onError }: Props) => { return ( <SettingList title="System Setting"> + <SettingItem> + <ListItemText primary="Tun Mode" /> + <GuardState + value={enable_tun_mode} + valueProps="checked" + onCatch={onError} + onFormat={onSwitchFormat} + onChange={(e) => onChangeData({ enable_tun_mode: e })} + onGuard={(e) => patchVergeConfig({ enable_tun_mode: e })} + > + <Switch edge="end" /> + </GuardState> + </SettingItem> + <SettingItem> <ListItemText primary="Auto Launch" /> <GuardState diff --git a/src/services/types.ts b/src/services/types.ts index 80eb09916b26e6c38101a3343b1979b2eaae525e..8843766c76feb1e1290a248154c9138233de147f 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -113,6 +113,7 @@ export namespace CmdType { theme_mode?: "light" | "dark"; theme_blur?: boolean; traffic_graph?: boolean; + enable_tun_mode?: boolean; enable_auto_launch?: boolean; enable_system_proxy?: boolean; enable_proxy_guard?: boolean;