Skip to content

Commit

Permalink
feat: add kde support for linux
Browse files Browse the repository at this point in the history
  • Loading branch information
SafeSmallPace committed Sep 9, 2023
1 parent 41c765d commit b34c417
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 71 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ description = "A library for set/get system proxy. Supports Windows, macOS and l
[dependencies]
thiserror = "1"

[target.'cfg(target_os = "linux")'.dependencies]
xdg = "^2.5"

[target.'cfg(target_os = "macos")'.dependencies]
interfaces = "0.0.8"

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# sysproxy-rs

A library for set/get system proxy. Supports Windows, macOS and linux (via gsettings).
A library for set/get system proxy. Supports Windows, macOS and linux (via gsettings/kconfig).
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ pub enum Error {

#[error("failed to get default network interface")]
NetworkInterface,

#[error("failed to set proxy for this environment")]
NotSupport,

#[cfg(target_os = "linux")]
#[error(transparent)]
Xdg(#[from] xdg::BaseDirectoriesError),
}

pub type Result<T> = std::result::Result<T, Error>;
Expand Down
320 changes: 250 additions & 70 deletions src/linux.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{Error, Result, Sysproxy};
use std::{process::Command, str::from_utf8};
use std::{env, process::Command, str::from_utf8};
use xdg;

const CMD_KEY: &str = "org.gnome.system.proxy";

Expand Down Expand Up @@ -42,27 +43,80 @@ impl Sysproxy {
}

pub fn get_enable() -> Result<bool> {
let mode = gsettings().args(["get", CMD_KEY, "mode"]).output()?;
let mode = from_utf8(&mode.stdout).or(Err(Error::ParseStr))?.trim();
Ok(mode == "'manual'")
match env::var("XDG_CURRENT_DESKTOP").unwrap_or_default().as_str() {
"GNOME" => {
let mode = gsettings().args(["get", CMD_KEY, "mode"]).output()?;
let mode = from_utf8(&mode.stdout).or(Err(Error::ParseStr))?.trim();
Ok(mode == "'manual'")
}
"KDE" => {
let xdg_dir = xdg::BaseDirectories::new()?;
let config = xdg_dir.get_config_file("kioslaverc");
let config = config.to_str().ok_or(Error::ParseStr)?;

let mode = kreadconfig()
.args([
"--file",
config,
"--group",
"Proxy Settings",
"--key",
"ProxyType",
])
.output()?;
let mode = from_utf8(&mode.stdout).or(Err(Error::ParseStr))?.trim();
Ok(mode == "1")
}
_ => Err(Error::NotSupport),
}
}

pub fn get_bypass() -> Result<String> {
let bypass = gsettings()
.args(["get", CMD_KEY, "ignore-hosts"])
.output()?;
let bypass = from_utf8(&bypass.stdout).or(Err(Error::ParseStr))?.trim();

let bypass = bypass.strip_prefix('[').unwrap_or(bypass);
let bypass = bypass.strip_suffix(']').unwrap_or(bypass);

let bypass = bypass
.split(',')
.map(|h| strip_str(h.trim()))
.collect::<Vec<&str>>()
.join(",");

Ok(bypass)
match env::var("XDG_CURRENT_DESKTOP").unwrap_or_default().as_str() {
"GNOME" => {
let bypass = gsettings()
.args(["get", CMD_KEY, "ignore-hosts"])
.output()?;
let bypass = from_utf8(&bypass.stdout).or(Err(Error::ParseStr))?.trim();

let bypass = bypass.strip_prefix('[').unwrap_or(bypass);
let bypass = bypass.strip_suffix(']').unwrap_or(bypass);

let bypass = bypass
.split(',')
.map(|h| strip_str(h.trim()))
.collect::<Vec<&str>>()
.join(",");

Ok(bypass)
}
"KDE" => {
let xdg_dir = xdg::BaseDirectories::new()?;
let config = xdg_dir.get_config_file("kioslaverc");
let config = config.to_str().ok_or(Error::ParseStr)?;

let bypass = kreadconfig()
.args([
"--file",
config,
"--group",
"Proxy Settings",
"--key",
"NoProxyFor",
])
.output()?;
let bypass = from_utf8(&bypass.stdout).or(Err(Error::ParseStr))?.trim();

let bypass = bypass
.split(',')
.map(|h| strip_str(h.trim()))
.collect::<Vec<&str>>()
.join(",");

Ok(bypass)
}
_ => Err(Error::NotSupport),
}
}

pub fn get_http() -> Result<Sysproxy> {
Expand All @@ -78,34 +132,80 @@ impl Sysproxy {
}

pub fn set_enable(&self) -> Result<()> {
let mode = if self.enable { "'manual'" } else { "'none'" };
gsettings().args(["set", CMD_KEY, "mode", mode]).status()?;
Ok(())
match env::var("XDG_CURRENT_DESKTOP").unwrap_or_default().as_str() {
"GNOME" => {
let mode = if self.enable { "'manual'" } else { "'none'" };
gsettings().args(["set", CMD_KEY, "mode", mode]).status()?;
Ok(())
}
"KDE" => {
let xdg_dir = xdg::BaseDirectories::new()?;
let config = xdg_dir.get_config_file("kioslaverc");
let config = config.to_str().ok_or(Error::ParseStr)?;
let mode = if self.enable { "1" } else { "0" };
kwriteconfig()
.args([
"--file",
config,
"--group",
"Proxy Settings",
"--key",
"ProxyType",
mode,
])
.status()?;
Ok(())
}
_ => Err(Error::NotSupport),
}
}

pub fn set_bypass(&self) -> Result<()> {
let bypass = self
.bypass
.split(',')
.map(|h| {
let mut host = String::from(h.trim());
if !host.starts_with('\'') && !host.starts_with('"') {
host = String::from("'") + &host;
}
if !host.ends_with('\'') && !host.ends_with('"') {
host = host + "'";
}
host
})
.collect::<Vec<String>>()
.join(", ");

let bypass = format!("[{bypass}]");

gsettings()
.args(["set", CMD_KEY, "ignore-hosts", bypass.as_str()])
.status()?;
Ok(())
match env::var("XDG_CURRENT_DESKTOP").unwrap_or_default().as_str() {
"GNOME" => {
let bypass = self
.bypass
.split(',')
.map(|h| {
let mut host = String::from(h.trim());
if !host.starts_with('\'') && !host.starts_with('"') {
host = String::from("'") + &host;
}
if !host.ends_with('\'') && !host.ends_with('"') {
host = host + "'";
}
host
})
.collect::<Vec<String>>()
.join(", ");

let bypass = format!("[{bypass}]");

gsettings()
.args(["set", CMD_KEY, "ignore-hosts", bypass.as_str()])
.status()?;
Ok(())
}
"KDE" => {
let xdg_dir = xdg::BaseDirectories::new()?;
let config = xdg_dir.get_config_file("kioslaverc");
let config = config.to_str().ok_or(Error::ParseStr)?;

kwriteconfig()
.args([
"--file",
config,
"--group",
"Proxy Settings",
"--key",
"NoProxyFor",
self.bypass.as_str(),
])
.status()?;
Ok(())
}
_ => Err(Error::NotSupport),
}
}

pub fn set_http(&self) -> Result<()> {
Expand All @@ -125,39 +225,119 @@ fn gsettings() -> Command {
Command::new("gsettings")
}

fn kreadconfig() -> Command {
Command::new("kreadconfig5")
}

fn kwriteconfig() -> Command {
Command::new("kwriteconfig5")
}

fn set_proxy(proxy: &Sysproxy, service: &str) -> Result<()> {
let schema = format!("{CMD_KEY}.{service}");
let schema = schema.as_str();
match env::var("XDG_CURRENT_DESKTOP").unwrap_or_default().as_str() {
"GNOME" => {
let schema = format!("{CMD_KEY}.{service}");
let schema = schema.as_str();

let host = format!("'{}'", proxy.host);
let host = host.as_str();
let port = format!("{}", proxy.port);
let port = port.as_str();
let host = format!("'{}'", proxy.host);
let host = host.as_str();
let port = format!("{}", proxy.port);
let port = port.as_str();

gsettings().args(["set", schema, "host", host]).status()?;
gsettings().args(["set", schema, "port", port]).status()?;
gsettings().args(["set", schema, "host", host]).status()?;
gsettings().args(["set", schema, "port", port]).status()?;

Ok(())
Ok(())
}
"KDE" => {
let xdg_dir = xdg::BaseDirectories::new()?;
let config = xdg_dir.get_config_file("kioslaverc");
let config = config.to_str().ok_or(Error::ParseStr)?;

let key = format!("{service}Proxy");
let key = key.as_str();

let service = match service {
"socks" => "socks",
_ => "http",
};

let host = format!("{}", proxy.host);
let host = host.as_str();
let port = format!("{}", proxy.port);
let port = port.as_str();

let schema = format!("{service}://{host} {port}");
let schema = schema.as_str();

kwriteconfig()
.args([
"--file",
config,
"--group",
"Proxy Settings",
"--key",
key,
schema,
])
.status()?;

Ok(())
}
_ => Err(Error::NotSupport),
}
}

fn get_proxy(service: &str) -> Result<Sysproxy> {
let schema = format!("{CMD_KEY}.{service}");
let schema = schema.as_str();

let host = gsettings().args(["get", schema, "host"]).output()?;
let host = from_utf8(&host.stdout).or(Err(Error::ParseStr))?.trim();
let host = strip_str(host);

let port = gsettings().args(["get", schema, "port"]).output()?;
let port = from_utf8(&port.stdout).or(Err(Error::ParseStr))?.trim();
let port = port.parse().unwrap_or(80u16);

Ok(Sysproxy {
enable: false,
host: String::from(host),
port,
bypass: "".into(),
})
match env::var("XDG_CURRENT_DESKTOP").unwrap_or_default().as_str() {
"GNOME" => {
let schema = format!("{CMD_KEY}.{service}");
let schema = schema.as_str();

let host = gsettings().args(["get", schema, "host"]).output()?;
let host = from_utf8(&host.stdout).or(Err(Error::ParseStr))?.trim();
let host = strip_str(host);

let port = gsettings().args(["get", schema, "port"]).output()?;
let port = from_utf8(&port.stdout).or(Err(Error::ParseStr))?.trim();
let port = port.parse().unwrap_or(80u16);

Ok(Sysproxy {
enable: false,
host: String::from(host),
port,
bypass: "".into(),
})
}
"KDE" => {
let xdg_dir = xdg::BaseDirectories::new()?;
let config = xdg_dir.get_config_file("kioslaverc");
let config = config.to_str().ok_or(Error::ParseStr)?;

let key = format!("{service}Proxy");
let key = key.as_str();

let schema = kreadconfig()
.args(["--file", config, "--group", "Proxy Settings", "--key", key])
.output()?;
let schema = from_utf8(&schema.stdout).or(Err(Error::ParseStr))?.trim();
let schema = schema
.trim_start_matches("http://")
.trim_start_matches("socks://");
let schema = schema.split_once(' ').ok_or(Error::ParseStr)?;

let host = strip_str(schema.0);
let port = schema.1.parse().unwrap_or(80u16);

Ok(Sysproxy {
enable: false,
host: String::from(host),
port,
bypass: "".into(),
})
}
_ => Err(Error::NotSupport),
}
}

fn strip_str<'a>(text: &'a str) -> &'a str {
Expand Down

0 comments on commit b34c417

Please sign in to comment.