diff --git a/Cargo.lock b/Cargo.lock index f87d5dceb..94d806983 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1205,6 +1205,7 @@ dependencies = [ "wayrs-protocols", "x11rb-async", "zbus", + "zbus_macros", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b0ad018f8..4bfe8f4d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ pipewire = ["dep:pipewire"] notmuch = ["dep:notmuch"] maildir = ["dep:maildir", "glob"] icu_calendar = ["dep:icu_datetime", "dep:icu_calendar", "dep:icu_locid"] -debug_borders = [] # Make widgets' borders visible +debug_borders = [] # Make widgets' borders visible [package.metadata.docs.rs] features = ["maildir", "notmuch"] @@ -30,12 +30,22 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] async-trait = "0.1" -backon = { version = "1.2", default-features = false, features = ["tokio-sleep"] } +backon = { version = "1.2", default-features = false, features = [ + "tokio-sleep", +] } base64 = { version = "0.22.1" } calibright = { version = "0.1.9", features = ["watch"] } -chrono = { version = "0.4", default-features = false, features = ["clock", "unstable-locales"] } +chrono = { version = "0.4", default-features = false, features = [ + "clock", + "unstable-locales", +] } chrono-tz = { version = "0.10", features = ["serde"] } -clap = { version = "4.0", default-features = false, features = ["std", "derive", "help", "usage"] } +clap = { version = "4.0", default-features = false, features = [ + "std", + "derive", + "help", + "usage", +] } dirs = "5.0" env_logger = "0.11" futures = { version = "0.3.31", default-features = false } @@ -77,8 +87,11 @@ thiserror = "2.0" toml = { version = "0.8", features = ["preserve_order"] } unicode-segmentation = "1.10.1" wayrs-client = { version = "1.0", features = ["tokio"] } -wayrs-protocols = { version = "0.14", features = ["wlr-foreign-toplevel-management-unstable-v1"] } -zbus = { version = "5", default-features = false, features = ["tokio"] } +wayrs-protocols = { version = "0.14", features = [ + "wlr-foreign-toplevel-management-unstable-v1", +] } +zbus = { version = "5.1.1", default-features = false, features = ["tokio"] } +zbus_macros = "5.1.1" x11rb-async = { version = "0.13.1", features = ["xkb"] } [dependencies.tokio] diff --git a/src/blocks/net.rs b/src/blocks/net.rs index d641d5303..11a10ed44 100644 --- a/src/blocks/net.rs +++ b/src/blocks/net.rs @@ -25,13 +25,15 @@ //! `graph_down` | Download speed graph | Text | - //! `graph_up` | Upload speed graph | Text | - //! `device` | The name of device | Text | - -//! `ssid` | Netfork SSID (WiFi only) | Text | - +//! `ssid` | Network SSID (WiFi only) | Text | - +//! `connection_name` | Connection name for Ethernet| Text | - //! `frequency` | WiFi frequency | Number | Hz //! `signal_strength` | WiFi signal | Number | % //! `bitrate` | WiFi connection bitrate | Number | Bits per second //! `ip` | IPv4 address of the iface | Text | - //! `ipv6` | IPv6 address of the iface | Text | - //! `nameserver` | Nameserver | Text | - +//! `connection_name` | Connection name for Ethernet| Text | - //! //! # Example //! @@ -157,7 +159,8 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> { "graph_up" => Value::text(util::format_bar_graph(&tx_hist)), [if let Some(v) = device.ip] "ip" => Value::text(v.to_string()), [if let Some(v) = device.ipv6] "ipv6" => Value::text(v.to_string()), - [if let Some(v) = device.ssid()] "ssid" => Value::text(v), + [if let Some(v) = device.ssid()] "ssid" => Value::text(v), // Display SSID for WiFi + [if let Some(ref v) = device.ethernet_id] "connection_name" => Value::text(v.clone()), // Convert &String to String [if let Some(v) = device.frequency()] "frequency" => Value::hertz(v), [if let Some(v) = device.bitrate()] "bitrate" => Value::bits(v), [if let Some(v) = device.signal()] "signal_strength" => Value::percents(v), diff --git a/src/netlink.rs b/src/netlink.rs index 9cab03577..2faa4ad5c 100644 --- a/src/netlink.rs +++ b/src/netlink.rs @@ -16,6 +16,14 @@ use std::path::Path; use crate::errors::*; use crate::util; +use zbus::Connection; // Add zbus for D-Bus communication +use zbus_macros::proxy; // Use the proxy attribute macro instead of dbus_proxy + +#[proxy(interface = "org.freedesktop.NetworkManager.Connection.Active")] +trait ActiveConnection { + fn id(&self) -> zbus::Result; +} + // From `linux/rtnetlink.h` const RT_SCOPE_HOST: c_uchar = 254; @@ -28,6 +36,7 @@ pub struct NetDevice { pub icon: &'static str, pub tun_wg_ppp: bool, pub nameservers: Vec, + pub ethernet_id: Option, } #[derive(Debug, Default)] @@ -72,6 +81,12 @@ impl NetDevice { .await .error("Failed to read nameservers")?; + let connection_name = if wifi_info.is_none() { + get_connection_name(&iface.name).await? + } else { + None + }; + // TODO: use netlink for the these too // I don't believe that this should ever change, so set it now: let path = Path::new("/sys/class/net").join(&iface.name); @@ -102,6 +117,7 @@ impl NetDevice { icon, tun_wg_ppp: tun | wg | ppp, nameservers, + ethernet_id: connection_name, // Store connection name for Ethernet })) } @@ -455,6 +471,67 @@ async fn read_nameservers() -> Result> { Ok(nameservers) } +async fn get_connection_name(iface_name: &str) -> Result> { + let connection = Connection::system() + .await + .error("Failed to connect to D-Bus")?; + let proxy = zbus::Proxy::new( + &connection, + "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager", + "org.freedesktop.NetworkManager", + ) + .await + .error("Failed to create D-Bus proxy")?; + + let active_connections: Vec = proxy + .call("ActiveConnections", &()) + .await + .error("Failed to get active connections")?; + + for path in active_connections { + let active_proxy = zbus::Proxy::new( + &connection, + "org.freedesktop.NetworkManager", + path.as_str(), + "org.freedesktop.NetworkManager.Connection.Active", + ) + .await + .error("Failed to create active connection proxy")?; + + let devices: Vec = active_proxy + .get_property("Devices") + .await + .error("Failed to get devices for connection")?; + + for device_path in devices { + let device_proxy = zbus::Proxy::new( + &connection, + "org.freedesktop.NetworkManager", + device_path.as_str(), + "org.freedesktop.NetworkManager.Device", + ) + .await + .error("Failed to create device proxy")?; + + let device_iface: String = device_proxy + .get_property("Interface") + .await + .error("Failed to get device interface")?; + + if device_iface == iface_name { + let connection_id: String = active_proxy + .get_property("Id") + .await + .error("Failed to get connection ID")?; + return Ok(Some(connection_id)); + } + } + } + + Ok(None) +} + // Source: https://www.kernel.org/doc/Documentation/networking/operstates.txt #[derive(Debug, PartialEq, Eq)] pub enum Operstate {