sysopt.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. use crate::{
  2. config::{Config, IVerge},
  3. log_err,
  4. };
  5. use anyhow::{anyhow, Result};
  6. use auto_launch::{AutoLaunch, AutoLaunchBuilder};
  7. use once_cell::sync::OnceCell;
  8. use parking_lot::Mutex;
  9. use std::env::current_exe;
  10. use std::sync::Arc;
  11. use sysproxy::{Autoproxy, Sysproxy};
  12. use tauri::async_runtime::Mutex as TokioMutex;
  13. pub struct Sysopt {
  14. /// current system proxy setting
  15. cur_sysproxy: Arc<Mutex<Option<Sysproxy>>>,
  16. /// record the original system proxy
  17. /// recover it when exit
  18. old_sysproxy: Arc<Mutex<Option<Sysproxy>>>,
  19. /// current auto proxy setting
  20. cur_autoproxy: Arc<Mutex<Option<Autoproxy>>>,
  21. /// record the original auto proxy
  22. /// recover it when exit
  23. old_autoproxy: Arc<Mutex<Option<Autoproxy>>>,
  24. /// helps to auto launch the app
  25. auto_launch: Arc<Mutex<Option<AutoLaunch>>>,
  26. /// record whether the guard async is running or not
  27. guard_state: Arc<TokioMutex<bool>>,
  28. }
  29. #[cfg(target_os = "windows")]
  30. static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;<local>";
  31. #[cfg(target_os = "linux")]
  32. static DEFAULT_BYPASS: &str = "localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,::1";
  33. #[cfg(target_os = "macos")]
  34. static DEFAULT_BYPASS: &str =
  35. "127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,localhost,*.local,*.crashlytics.com,<local>";
  36. fn get_bypass() -> String {
  37. let bypass = DEFAULT_BYPASS.to_string();
  38. let res = {
  39. let verge = Config::verge();
  40. let verge = verge.latest();
  41. verge.system_proxy_bypass.clone()
  42. };
  43. let custom_bypass = match res {
  44. Some(bypass) => bypass,
  45. None => "".to_string(),
  46. };
  47. #[cfg(target_os = "windows")]
  48. let bypass = if custom_bypass.is_empty() {
  49. bypass
  50. } else {
  51. format!("{};{}", bypass, custom_bypass)
  52. };
  53. #[cfg(not(target_os = "windows"))]
  54. let bypass = if custom_bypass.is_empty() {
  55. bypass
  56. } else {
  57. format!("{},{}", bypass, custom_bypass)
  58. };
  59. bypass
  60. }
  61. impl Sysopt {
  62. pub fn global() -> &'static Sysopt {
  63. static SYSOPT: OnceCell<Sysopt> = OnceCell::new();
  64. SYSOPT.get_or_init(|| Sysopt {
  65. cur_sysproxy: Arc::new(Mutex::new(None)),
  66. old_sysproxy: Arc::new(Mutex::new(None)),
  67. cur_autoproxy: Arc::new(Mutex::new(None)),
  68. old_autoproxy: Arc::new(Mutex::new(None)),
  69. auto_launch: Arc::new(Mutex::new(None)),
  70. guard_state: Arc::new(TokioMutex::new(false)),
  71. })
  72. }
  73. /// init the sysproxy
  74. pub fn init_sysproxy(&self) -> Result<()> {
  75. let port = Config::verge()
  76. .latest()
  77. .verge_mixed_port
  78. .unwrap_or(Config::clash().data().get_mixed_port());
  79. let pac_port = IVerge::get_singleton_port();
  80. let (enable, pac) = {
  81. let verge = Config::verge();
  82. let verge = verge.latest();
  83. (
  84. verge.enable_system_proxy.unwrap_or(false),
  85. verge.proxy_auto_config.unwrap_or(false),
  86. )
  87. };
  88. let mut sys = Sysproxy {
  89. enable,
  90. host: String::from("127.0.0.1"),
  91. port,
  92. bypass: get_bypass(),
  93. };
  94. let mut auto = Autoproxy {
  95. enable,
  96. url: format!("http://127.0.0.1:{pac_port}/commands/pac"),
  97. };
  98. if pac {
  99. sys.enable = false;
  100. let old = Sysproxy::get_system_proxy().ok();
  101. sys.set_system_proxy()?;
  102. *self.old_sysproxy.lock() = old;
  103. *self.cur_sysproxy.lock() = Some(sys);
  104. let old = Autoproxy::get_auto_proxy().ok();
  105. auto.set_auto_proxy()?;
  106. *self.old_autoproxy.lock() = old;
  107. *self.cur_autoproxy.lock() = Some(auto);
  108. } else {
  109. auto.enable = false;
  110. let old = Autoproxy::get_auto_proxy().ok();
  111. auto.set_auto_proxy()?;
  112. *self.old_autoproxy.lock() = old;
  113. *self.cur_autoproxy.lock() = Some(auto);
  114. let old = Sysproxy::get_system_proxy().ok();
  115. sys.set_system_proxy()?;
  116. *self.old_sysproxy.lock() = old;
  117. *self.cur_sysproxy.lock() = Some(sys);
  118. }
  119. // run the system proxy guard
  120. self.guard_proxy();
  121. Ok(())
  122. }
  123. /// update the system proxy
  124. pub fn update_sysproxy(&self) -> Result<()> {
  125. let mut cur_sysproxy = self.cur_sysproxy.lock();
  126. let old_sysproxy = self.old_sysproxy.lock();
  127. let mut cur_autoproxy = self.cur_autoproxy.lock();
  128. let old_autoproxy = self.old_autoproxy.lock();
  129. let (enable, pac) = {
  130. let verge = Config::verge();
  131. let verge = verge.latest();
  132. (
  133. verge.enable_system_proxy.unwrap_or(false),
  134. verge.proxy_auto_config.unwrap_or(false),
  135. )
  136. };
  137. if pac && (cur_autoproxy.is_none() || old_autoproxy.is_none()) {
  138. drop(cur_autoproxy);
  139. drop(old_autoproxy);
  140. return self.init_sysproxy();
  141. }
  142. if !pac && (cur_sysproxy.is_none() || old_sysproxy.is_none()) {
  143. drop(cur_sysproxy);
  144. drop(old_sysproxy);
  145. return self.init_sysproxy();
  146. }
  147. let port = Config::verge()
  148. .latest()
  149. .verge_mixed_port
  150. .unwrap_or(Config::clash().data().get_mixed_port());
  151. let pac_port = IVerge::get_singleton_port();
  152. let mut sysproxy = cur_sysproxy.take().unwrap();
  153. sysproxy.bypass = get_bypass();
  154. sysproxy.port = port;
  155. let mut autoproxy = cur_autoproxy.take().unwrap();
  156. autoproxy.url = format!("http://127.0.0.1:{pac_port}/commands/pac");
  157. if pac {
  158. sysproxy.enable = false;
  159. sysproxy.set_system_proxy()?;
  160. *cur_sysproxy = Some(sysproxy);
  161. autoproxy.enable = enable;
  162. autoproxy.set_auto_proxy()?;
  163. *cur_autoproxy = Some(autoproxy);
  164. } else {
  165. autoproxy.enable = false;
  166. autoproxy.set_auto_proxy()?;
  167. *cur_autoproxy = Some(autoproxy);
  168. sysproxy.enable = enable;
  169. sysproxy.set_system_proxy()?;
  170. *cur_sysproxy = Some(sysproxy);
  171. }
  172. Ok(())
  173. }
  174. /// reset the sysproxy
  175. pub fn reset_sysproxy(&self) -> Result<()> {
  176. let mut cur_sysproxy = self.cur_sysproxy.lock();
  177. let mut old_sysproxy = self.old_sysproxy.lock();
  178. let mut cur_autoproxy = self.cur_autoproxy.lock();
  179. let mut old_autoproxy = self.old_autoproxy.lock();
  180. let cur_sysproxy = cur_sysproxy.take();
  181. let cur_autoproxy = cur_autoproxy.take();
  182. if let Some(mut old) = old_sysproxy.take() {
  183. // 如果原代理和当前代理 端口一致,就disable关闭,否则就恢复原代理设置
  184. // 当前没有设置代理的时候,不确定旧设置是否和当前一致,全关了
  185. let port_same = cur_sysproxy.map_or(true, |cur| old.port == cur.port);
  186. if old.enable && port_same {
  187. old.enable = false;
  188. log::info!(target: "app", "reset proxy by disabling the original proxy");
  189. } else {
  190. log::info!(target: "app", "reset proxy to the original proxy");
  191. }
  192. old.set_system_proxy()?;
  193. } else if let Some(mut cur @ Sysproxy { enable: true, .. }) = cur_sysproxy {
  194. // 没有原代理,就按现在的代理设置disable即可
  195. log::info!(target: "app", "reset proxy by disabling the current proxy");
  196. cur.enable = false;
  197. cur.set_system_proxy()?;
  198. } else {
  199. log::info!(target: "app", "reset proxy with no action");
  200. }
  201. if let Some(mut old) = old_autoproxy.take() {
  202. // 如果原代理和当前代理 URL一致,就disable关闭,否则就恢复原代理设置
  203. // 当前没有设置代理的时候,不确定旧设置是否和当前一致,全关了
  204. let url_same = cur_autoproxy.map_or(true, |cur| old.url == cur.url);
  205. if old.enable && url_same {
  206. old.enable = false;
  207. log::info!(target: "app", "reset proxy by disabling the original proxy");
  208. } else {
  209. log::info!(target: "app", "reset proxy to the original proxy");
  210. }
  211. old.set_auto_proxy()?;
  212. } else if let Some(mut cur @ Autoproxy { enable: true, .. }) = cur_autoproxy {
  213. // 没有原代理,就按现在的代理设置disable即可
  214. log::info!(target: "app", "reset proxy by disabling the current proxy");
  215. cur.enable = false;
  216. cur.set_auto_proxy()?;
  217. } else {
  218. log::info!(target: "app", "reset proxy with no action");
  219. }
  220. Ok(())
  221. }
  222. /// init the auto launch
  223. pub fn init_launch(&self) -> Result<()> {
  224. let app_exe = current_exe()?;
  225. // let app_exe = dunce::canonicalize(app_exe)?;
  226. let app_name = app_exe
  227. .file_stem()
  228. .and_then(|f| f.to_str())
  229. .ok_or(anyhow!("failed to get file stem"))?;
  230. let app_path = app_exe
  231. .as_os_str()
  232. .to_str()
  233. .ok_or(anyhow!("failed to get app_path"))?
  234. .to_string();
  235. // fix issue #26
  236. #[cfg(target_os = "windows")]
  237. let app_path = format!("\"{app_path}\"");
  238. // use the /Applications/Clash Verge.app path
  239. #[cfg(target_os = "macos")]
  240. let app_path = (|| -> Option<String> {
  241. let path = std::path::PathBuf::from(&app_path);
  242. let path = path.parent()?.parent()?.parent()?;
  243. let extension = path.extension()?.to_str()?;
  244. match extension == "app" {
  245. true => Some(path.as_os_str().to_str()?.to_string()),
  246. false => None,
  247. }
  248. })()
  249. .unwrap_or(app_path);
  250. // fix #403
  251. #[cfg(target_os = "linux")]
  252. let app_path = {
  253. use crate::core::handle::Handle;
  254. use tauri::Manager;
  255. let handle = Handle::global();
  256. match handle.app_handle.lock().as_ref() {
  257. Some(app_handle) => {
  258. let appimage = app_handle.env().appimage;
  259. appimage
  260. .and_then(|p| p.to_str().map(|s| s.to_string()))
  261. .unwrap_or(app_path)
  262. }
  263. None => app_path,
  264. }
  265. };
  266. let auto = AutoLaunchBuilder::new()
  267. .set_app_name(app_name)
  268. .set_app_path(&app_path)
  269. .build()?;
  270. *self.auto_launch.lock() = Some(auto);
  271. Ok(())
  272. }
  273. /// update the startup
  274. pub fn update_launch(&self) -> Result<()> {
  275. let auto_launch = self.auto_launch.lock();
  276. if auto_launch.is_none() {
  277. drop(auto_launch);
  278. return self.init_launch();
  279. }
  280. let enable = { Config::verge().latest().enable_auto_launch };
  281. let enable = enable.unwrap_or(false);
  282. let auto_launch = auto_launch.as_ref().unwrap();
  283. match enable {
  284. true => auto_launch.enable()?,
  285. false => log_err!(auto_launch.disable()), // 忽略关闭的错误
  286. };
  287. Ok(())
  288. }
  289. /// launch a system proxy guard
  290. /// read config from file directly
  291. pub fn guard_proxy(&self) {
  292. use tokio::time::{sleep, Duration};
  293. let guard_state = self.guard_state.clone();
  294. tauri::async_runtime::spawn(async move {
  295. // if it is running, exit
  296. let mut state = guard_state.lock().await;
  297. if *state {
  298. return;
  299. }
  300. *state = true;
  301. drop(state);
  302. // default duration is 10s
  303. let mut wait_secs = 10u64;
  304. loop {
  305. sleep(Duration::from_secs(wait_secs)).await;
  306. let (enable, guard, guard_duration, pac) = {
  307. let verge = Config::verge();
  308. let verge = verge.latest();
  309. (
  310. verge.enable_system_proxy.unwrap_or(false),
  311. verge.enable_proxy_guard.unwrap_or(false),
  312. verge.proxy_guard_duration.unwrap_or(10),
  313. verge.proxy_auto_config.unwrap_or(false),
  314. )
  315. };
  316. // stop loop
  317. if !enable || !guard {
  318. break;
  319. }
  320. // update duration
  321. wait_secs = guard_duration;
  322. log::debug!(target: "app", "try to guard the system proxy");
  323. let port = {
  324. Config::verge()
  325. .latest()
  326. .verge_mixed_port
  327. .unwrap_or(Config::clash().data().get_mixed_port())
  328. };
  329. let pac_port = IVerge::get_singleton_port();
  330. if pac {
  331. let autoproxy = Autoproxy {
  332. enable: true,
  333. url: format!("http://127.0.0.1:{pac_port}/commands/pac"),
  334. };
  335. log_err!(autoproxy.set_auto_proxy());
  336. } else {
  337. let sysproxy = Sysproxy {
  338. enable: true,
  339. host: "127.0.0.1".into(),
  340. port,
  341. bypass: get_bypass(),
  342. };
  343. log_err!(sysproxy.set_system_proxy());
  344. }
  345. }
  346. let mut state = guard_state.lock().await;
  347. *state = false;
  348. drop(state);
  349. });
  350. }
  351. }