verge.rs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. use crate::{
  2. core::Clash,
  3. utils::{config, dirs, sysopt::SysProxyConfig},
  4. };
  5. use auto_launch::{AutoLaunch, AutoLaunchBuilder};
  6. use serde::{Deserialize, Serialize};
  7. use std::sync::Arc;
  8. use tauri::{async_runtime::Mutex, utils::platform::current_exe};
  9. /// ### `verge.yaml` schema
  10. #[derive(Default, Debug, Clone, Deserialize, Serialize)]
  11. pub struct VergeConfig {
  12. /// `light` or `dark`
  13. pub theme_mode: Option<String>,
  14. /// enable blur mode
  15. /// maybe be able to set the alpha
  16. pub theme_blur: Option<bool>,
  17. /// enable traffic graph default is true
  18. pub traffic_graph: Option<bool>,
  19. /// can the app auto startup
  20. pub enable_auto_launch: Option<bool>,
  21. /// set system proxy
  22. pub enable_system_proxy: Option<bool>,
  23. /// enable proxy guard
  24. pub enable_proxy_guard: Option<bool>,
  25. /// set system proxy bypass
  26. pub system_proxy_bypass: Option<String>,
  27. /// proxy guard duration
  28. pub proxy_guard_duration: Option<u64>,
  29. }
  30. static VERGE_CONFIG: &str = "verge.yaml";
  31. impl VergeConfig {
  32. pub fn new() -> Self {
  33. config::read_yaml::<VergeConfig>(dirs::app_home_dir().join(VERGE_CONFIG))
  34. }
  35. /// Save Verge App Config
  36. pub fn save_file(&self) -> Result<(), String> {
  37. config::save_yaml(
  38. dirs::app_home_dir().join(VERGE_CONFIG),
  39. self,
  40. Some("# The Config for Clash Verge App\n\n"),
  41. )
  42. }
  43. }
  44. /// Verge App abilities
  45. #[derive(Debug)]
  46. pub struct Verge {
  47. pub config: VergeConfig,
  48. pub old_sysproxy: Option<SysProxyConfig>,
  49. pub cur_sysproxy: Option<SysProxyConfig>,
  50. pub auto_launch: Option<AutoLaunch>,
  51. /// record whether the guard async is running or not
  52. guard_state: Arc<Mutex<bool>>,
  53. }
  54. impl Default for Verge {
  55. fn default() -> Self {
  56. Verge::new()
  57. }
  58. }
  59. impl Verge {
  60. pub fn new() -> Self {
  61. Verge {
  62. config: VergeConfig::new(),
  63. old_sysproxy: None,
  64. cur_sysproxy: None,
  65. auto_launch: None,
  66. guard_state: Arc::new(Mutex::new(false)),
  67. }
  68. }
  69. /// init the sysproxy
  70. pub fn init_sysproxy(&mut self, port: Option<String>) {
  71. if let Some(port) = port {
  72. let enable = self.config.enable_system_proxy.clone().unwrap_or(false);
  73. self.old_sysproxy = match SysProxyConfig::get_sys() {
  74. Ok(proxy) => Some(proxy),
  75. Err(_) => None,
  76. };
  77. let bypass = self.config.system_proxy_bypass.clone();
  78. let sysproxy = SysProxyConfig::new(enable, port, bypass);
  79. if enable {
  80. if sysproxy.set_sys().is_err() {
  81. log::error!("failed to set system proxy");
  82. }
  83. }
  84. self.cur_sysproxy = Some(sysproxy);
  85. }
  86. // launchs the system proxy guard
  87. Verge::guard_proxy(self.guard_state.clone());
  88. }
  89. /// reset the sysproxy
  90. pub fn reset_sysproxy(&mut self) {
  91. if let Some(sysproxy) = self.old_sysproxy.take() {
  92. match sysproxy.set_sys() {
  93. Ok(_) => self.cur_sysproxy = None,
  94. Err(_) => log::error!("failed to reset proxy for"),
  95. }
  96. }
  97. }
  98. /// init the auto launch
  99. pub fn init_launch(&mut self) {
  100. let app_exe = current_exe().unwrap();
  101. let app_exe = dunce::canonicalize(app_exe).unwrap();
  102. let app_name = app_exe.file_stem().unwrap().to_str().unwrap();
  103. let app_path = app_exe.as_os_str().to_str().unwrap();
  104. let auto = AutoLaunchBuilder::new()
  105. .set_app_name(app_name)
  106. .set_app_path(app_path)
  107. .build();
  108. self.auto_launch = Some(auto);
  109. }
  110. /// sync the startup when run the app
  111. pub fn sync_launch(&self) -> Result<(), String> {
  112. let enable = self.config.enable_auto_launch.clone().unwrap_or(false);
  113. if !enable {
  114. return Ok(());
  115. }
  116. if self.auto_launch.is_none() {
  117. return Err("should init the auto launch first".into());
  118. }
  119. let auto_launch = self.auto_launch.clone().unwrap();
  120. let is_enabled = auto_launch.is_enabled().unwrap_or(false);
  121. if !is_enabled {
  122. if let Err(_) = auto_launch.enable() {
  123. return Err("failed to enable auto-launch".into());
  124. }
  125. }
  126. Ok(())
  127. }
  128. /// update the startup
  129. fn update_launch(&mut self, enable: bool) -> Result<(), String> {
  130. let conf_enable = self.config.enable_auto_launch.clone().unwrap_or(false);
  131. if enable == conf_enable {
  132. return Ok(());
  133. }
  134. let auto_launch = self.auto_launch.clone().unwrap();
  135. let result = match enable {
  136. true => auto_launch.enable(),
  137. false => auto_launch.disable(),
  138. };
  139. match result {
  140. Ok(_) => Ok(()),
  141. Err(err) => {
  142. log::error!("{err}");
  143. Err("failed to set system startup info".into())
  144. }
  145. }
  146. }
  147. /// patch verge config
  148. /// There should be only one update at a time here
  149. /// so call the save_file at the end is savely
  150. pub fn patch_config(&mut self, patch: VergeConfig) -> Result<(), String> {
  151. // only change it
  152. if patch.theme_mode.is_some() {
  153. self.config.theme_mode = patch.theme_mode;
  154. }
  155. if patch.theme_blur.is_some() {
  156. self.config.theme_blur = patch.theme_blur;
  157. }
  158. if patch.traffic_graph.is_some() {
  159. self.config.traffic_graph = patch.traffic_graph;
  160. }
  161. // should update system startup
  162. if patch.enable_auto_launch.is_some() {
  163. let enable = patch.enable_auto_launch.unwrap();
  164. self.update_launch(enable)?;
  165. self.config.enable_auto_launch = Some(enable);
  166. }
  167. // should update system proxy
  168. if patch.enable_system_proxy.is_some() {
  169. let enable = patch.enable_system_proxy.unwrap();
  170. if let Some(mut sysproxy) = self.cur_sysproxy.take() {
  171. sysproxy.enable = enable;
  172. if sysproxy.set_sys().is_err() {
  173. self.cur_sysproxy = Some(sysproxy);
  174. log::error!("failed to set system proxy");
  175. return Err("failed to set system proxy".into());
  176. }
  177. self.cur_sysproxy = Some(sysproxy);
  178. }
  179. self.config.enable_system_proxy = Some(enable);
  180. }
  181. // should update system proxy too
  182. if patch.system_proxy_bypass.is_some() {
  183. let bypass = patch.system_proxy_bypass.unwrap();
  184. if let Some(mut sysproxy) = self.cur_sysproxy.take() {
  185. if sysproxy.enable {
  186. sysproxy.bypass = bypass.clone();
  187. if sysproxy.set_sys().is_err() {
  188. self.cur_sysproxy = Some(sysproxy);
  189. log::error!("failed to set system proxy");
  190. return Err("failed to set system proxy".into());
  191. }
  192. }
  193. self.cur_sysproxy = Some(sysproxy);
  194. }
  195. self.config.system_proxy_bypass = Some(bypass);
  196. }
  197. // proxy guard
  198. // only change it
  199. if patch.enable_proxy_guard.is_some() {
  200. self.config.enable_proxy_guard = patch.enable_proxy_guard;
  201. }
  202. if patch.proxy_guard_duration.is_some() {
  203. self.config.proxy_guard_duration = patch.proxy_guard_duration;
  204. }
  205. // relaunch the guard
  206. if patch.enable_system_proxy.is_some() || patch.enable_proxy_guard.is_some() {
  207. Verge::guard_proxy(self.guard_state.clone());
  208. }
  209. self.config.save_file()
  210. }
  211. }
  212. impl Verge {
  213. /// launch a system proxy guard
  214. /// read config from file directly
  215. pub fn guard_proxy(guard_state: Arc<Mutex<bool>>) {
  216. use tokio::time::{sleep, Duration};
  217. tauri::async_runtime::spawn(async move {
  218. // if it is running, exit
  219. let mut state = guard_state.lock().await;
  220. if *state {
  221. return;
  222. }
  223. *state = true;
  224. std::mem::drop(state);
  225. // default duration is 10s
  226. let mut wait_secs = 10u64;
  227. loop {
  228. sleep(Duration::from_secs(wait_secs)).await;
  229. log::debug!("[Guard]: heartbeat detection");
  230. let verge = Verge::new();
  231. let enable_proxy = verge.config.enable_system_proxy.unwrap_or(false);
  232. let enable_guard = verge.config.enable_proxy_guard.unwrap_or(false);
  233. let guard_duration = verge.config.proxy_guard_duration.unwrap_or(10);
  234. // update duration
  235. wait_secs = guard_duration;
  236. // stop loop
  237. if !enable_guard || !enable_proxy {
  238. break;
  239. }
  240. log::info!("[Guard]: try to guard proxy");
  241. let clash = Clash::new();
  242. match &clash.info.port {
  243. Some(port) => {
  244. let bypass = verge.config.system_proxy_bypass.clone();
  245. let sysproxy = SysProxyConfig::new(true, port.clone(), bypass);
  246. if let Err(err) = sysproxy.set_sys() {
  247. log::error!("[Guard]: {err}");
  248. log::error!("[Guard]: fail to set system proxy");
  249. }
  250. }
  251. None => log::error!("[Guard]: fail to parse clash port"),
  252. }
  253. }
  254. let mut state = guard_state.lock().await;
  255. *state = false;
  256. });
  257. }
  258. }