From 78774315cbd4d44baba07a14ecd852aa0eb65dc6 Mon Sep 17 00:00:00 2001 From: GyDi Date: Wed, 9 Mar 2022 19:48:32 +0800 Subject: [PATCH] feat: linux system proxy --- src-tauri/src/utils/sysopt.rs | 178 +++++++++++++++++++++++++++++----- 1 file changed, 156 insertions(+), 22 deletions(-) diff --git a/src-tauri/src/utils/sysopt.rs b/src-tauri/src/utils/sysopt.rs index 9344cc4..502f0ae 100755 --- a/src-tauri/src/utils/sysopt.rs +++ b/src-tauri/src/utils/sysopt.rs @@ -1,5 +1,5 @@ +use anyhow::Result; use serde::{Deserialize, Serialize}; -use std::io; #[cfg(target_os = "windows")] static DEFAULT_BYPASS: &str = "localhost;127.*;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.*;192.168.*;"; @@ -41,7 +41,7 @@ impl SysProxyConfig { #[cfg(target_os = "windows")] impl SysProxyConfig { /// Get the windows system proxy config - pub fn get_sys() -> io::Result { + pub fn get_sys() -> Result { use winreg::enums::*; use winreg::RegKey; @@ -59,7 +59,7 @@ impl SysProxyConfig { } /// Set the windows system proxy config - pub fn set_sys(&self) -> io::Result<()> { + pub fn set_sys(&self) -> Result<()> { use winreg::enums::*; use winreg::RegKey; let hkcu = RegKey::predef(HKEY_CURRENT_USER); @@ -72,14 +72,16 @@ impl SysProxyConfig { cur_var.set_value("ProxyEnable", &enable)?; cur_var.set_value("ProxyServer", &self.server)?; - cur_var.set_value("ProxyOverride", &self.bypass) + cur_var.set_value("ProxyOverride", &self.bypass)?; + + Ok(()) } } #[cfg(target_os = "macos")] impl SysProxyConfig { /// Get the macos system proxy config - pub fn get_sys() -> io::Result { + pub fn get_sys() -> Result { use std::process::Command; let http = macproxy::get_proxy(&["-getwebproxy", MACOS_SERVICE])?; @@ -122,7 +124,7 @@ impl SysProxyConfig { } /// Set the macos system proxy config - pub fn set_sys(&self) -> io::Result<()> { + pub fn set_sys(&self) -> Result<()> { use std::process::Command; let enable = self.enable; @@ -144,22 +146,20 @@ impl SysProxyConfig { #[cfg(target_os = "macos")] mod macproxy { use super::*; + use anyhow::bail; use std::process::Command; /// use networksetup /// get the target proxy config - pub(super) fn get_proxy(args: &[&str; 2]) -> io::Result<(String, String)> { + pub(super) fn get_proxy(args: &[&str; 2]) -> Result<(String, String)> { let output = Command::new("networksetup").args(args).output()?; - match std::str::from_utf8(&output.stdout) { - Ok(stdout) => { - let enable = parse(stdout, "Enabled:"); - let server = parse(stdout, "Server:"); - let port = parse(stdout, "Port:"); - let server = format!("{}:{}", server, port); - Ok((enable.into(), server)) - } - Err(_) => Err(io::Error::from_raw_os_error(1)), - } + + let stdout = std::str::from_utf8(&output.stdout)?; + let enable = parse(stdout, "Enabled:"); + let server = parse(stdout, "Server:"); + let port = parse(stdout, "Port:"); + let server = format!("{server}:{port}"); + Ok((enable.into(), server)) } /// use networksetup @@ -169,17 +169,17 @@ mod macproxy { device: &str, enable: bool, server: &str, - ) -> io::Result<()> { + ) -> Result<()> { let mut split = server.split(":"); - let domain = split.next(); + let host = split.next(); let port = split.next(); // can not parse the field - if domain.is_none() || port.is_none() { - return Err(io::Error::from_raw_os_error(1)); + if host.is_none() || port.is_none() { + bail!("failed to parse the server into host:port"); } - let args = vec![target, device, domain.unwrap(), port.unwrap()]; + let args = vec![target, device, host.unwrap(), port.unwrap()]; Command::new("networksetup").args(&args).status()?; let target_state = String::from(target) + "state"; @@ -230,3 +230,137 @@ mod macproxy { dbg!(sysproxy.set_sys().unwrap()); } } + +/// +/// Linux Desktop System Proxy Supports +/// by using `gsettings` +#[cfg(target_os = "linux")] +impl SysProxyConfig { + /// Get the system proxy config [http/https/socks] + pub fn get_sys() -> Result { + use std::process::Command; + + let schema = "org.gnome.system.proxy"; + + // get enable + let mode = Command::new("gsettings") + .args(["get", schema, "mode"]) + .output()?; + let mode = std::str::from_utf8(&mode.stdout)?; + let enable = mode == "manual"; + + // get bypass + // Todo: parse the ignore-hosts + // ['aaa', 'bbb'] -> aaa,bbb + let ignore = Command::new("gsettings") + .args(["get", schema, "ignore-hosts"]) + .output()?; + let ignore = std::str::from_utf8(&ignore.stdout)?; + let bypass = ignore.to_string(); + + let http = Self::get_proxy("http")?; + let https = Self::get_proxy("https")?; + let socks = Self::get_proxy("socks")?; + + let mut server = "".into(); + + if socks.len() > 0 { + server = socks; + } + if https.len() > 0 { + server = https; + } + if http.len() > 0 { + server = http; + } + + Ok(SysProxyConfig { + enable, + server, + bypass, + }) + } + + /// Get the system proxy config [http/https/socks] + pub fn set_sys(&self) -> Result<()> { + use anyhow::bail; + use std::process::Command; + + let enable = self.enable; + let server = self.server.as_str(); + let bypass = self.bypass.clone(); + let schema = "org.gnome.system.proxy"; + + if enable { + let mut split = server.split(":"); + let host = split.next(); + let port = split.next(); + + if port.is_none() { + bail!("failed to parse the port"); + } + + let host = format!("'{}'", host.unwrap_or("127.0.0.1")); + let host = host.as_str(); + let port = port.unwrap(); + + let http = format!("{schema}.http"); + Command::new("gsettings") + .args(["set", http.as_str(), "host", host]) + .status()?; + Command::new("gsettings") + .args(["set", http.as_str(), "port", port]) + .status()?; + + let https = format!("{schema}.https"); + Command::new("gsettings") + .args(["set", https.as_str(), "host", host]) + .status()?; + Command::new("gsettings") + .args(["set", https.as_str(), "port", port]) + .status()?; + + let socks = format!("{schema}.socks"); + Command::new("gsettings") + .args(["set", socks.as_str(), "host", host]) + .status()?; + Command::new("gsettings") + .args(["set", socks.as_str(), "port", port]) + .status()?; + + // set bypass + // Todo: parse the ignore-hosts + // aaa,bbb,cccc -> ['aaa', 'bbb', 'ccc'] + Command::new("gsettings") + .args(["set", schema, "ignore-hosts", bypass.as_str()]) // todo + .status()?; + } + + let mode = if enable { "'manual'" } else { "'none'" }; + Command::new("gsettings") + .args(["set", schema, "mode", mode]) + .status()?; + + Ok(()) + } + + /// help function + fn get_proxy(typ: &str) -> Result { + use std::process::Command; + + let schema = format!("org.gnome.system.proxy.{typ}"); + let schema = schema.as_str(); + + let host = Command::new("gsettings") + .args(["get", schema, "host"]) + .output()?; + let host = std::str::from_utf8(&host.stdout)?; + + let port = Command::new("gsettings") + .args(["get", schema, "port"]) + .output()?; + let port = std::str::from_utf8(&port.stdout)?; + + Ok(format!("{host}:{port}")) + } +}