use std::time::Duration;
use std::sync::Arc;
use std::net::Ipv4Addr;
use dbus::{Error, Path};
use dbus::blocking::{Connection, Proxy};
use dbus::arg::RefArg;
use nmdbus::NetworkManager as DbusNetworkManager;
use nmdbus::device::Device as DeviceTrait;
use nmdbus::device_modem::DeviceModem;
use nmdbus::ip4config::IP4Config;
const DBUS_NAME: &str = "org.freedesktop.NetworkManager";
const DBUS_PATH: &str = "/org/freedesktop/NetworkManager";
const TIMEOUT: Duration = Duration::from_secs(2);
#[derive(Clone)]
struct Dbus {
conn: Arc<Connection>
}
impl Dbus {
fn connect() -> Result<Self, Error> {
Connection::new_system()
.map(Arc::new)
.map(|conn| Self { conn })
}
fn proxy<'a, 'b>(
&'b self,
path: impl Into<Path<'a>>
) -> Proxy<'a, &'b Connection> {
self.conn.with_proxy(DBUS_NAME, path, TIMEOUT)
}
}
#[derive(Clone)]
pub struct NetworkManager {
dbus: Dbus
}
impl NetworkManager {
pub fn connect() -> Result<Self, Error> {
Dbus::connect()
.map(|dbus| Self { dbus })
}
pub fn devices(&self) -> Result<Vec<Device>, Error> {
let paths = self.dbus.proxy(DBUS_PATH).get_devices()?;
let devices = paths.into_iter()
.map(|path| {
Device {
dbus: self.dbus.clone(),
path
}
})
.collect();
Ok(devices)
}
}
pub struct Device {
dbus: Dbus,
path: Path<'static>
}
impl Device {
pub fn path(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).path()
}
pub fn interface(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).interface()
}
pub fn driver(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).driver()
}
pub fn state(&self) -> Result<DeviceState, Error> {
DeviceTrait::state(&self.dbus.proxy(&self.path))
.map(Into::into)
}
pub fn kind(&self) -> Result<DeviceKind, Error> {
self.dbus.proxy(&self.path).device_type()
.map(Into::into)
}
pub fn ipv4_config(&self) -> Result<Ipv4Config, Error> {
self.dbus.proxy(&self.path).ip4_config()
.map(|path| Ipv4Config {
dbus: self.dbus.clone(),
path
})
}
pub fn modem_apn(&self) -> Result<String, Error> {
self.dbus.proxy(&self.path).apn()
}
}
pub struct Ipv4Config {
dbus: Dbus,
path: Path<'static>
}
impl Ipv4Config {
pub fn addresses(&self) -> Result<Vec<Ipv4Addr>, Error> {
let data = self.dbus.proxy(&self.path).address_data()?;
let addrs = data.into_iter()
.filter_map(|mut d| d.remove("address"))
.filter_map(|addr| {
addr.as_str()?
.parse().ok()
})
.collect();
Ok(addrs)
}
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1")
)]
pub enum DeviceKind {
Unknown = 0,
Generic = 14,
Ethernet = 1,
Wifi = 2,
Unused1 = 3,
Unused2 = 4,
Bt = 5,
OlpcMesh = 6,
Wimax = 7,
Modem = 8,
Infiniband = 9,
Bond = 10,
Vlan = 11,
Adsl = 12,
Bridge = 13,
Team = 15,
Tun = 16,
IpTunnel = 17,
Macvlan = 18,
Vxlan = 19,
Veth = 20,
Macsec = 21,
Dummy = 22,
Ppp = 23,
OvsInterface = 24,
OvsPort = 25,
OvsBridge = 26,
Wpan = 27,
SixLowPan = 28,
Wireguard = 29,
WifiP2p = 30,
Vrf = 31
}
impl From<u32> for DeviceKind {
fn from(num: u32) -> Self {
if num > 31 {
Self::Unknown
} else {
unsafe {
*(&num as *const u32 as *const Self)
}
}
}
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(
feature = "serde",
derive(serde1::Serialize, serde1::Deserialize),
serde(crate = "serde1")
)]
pub enum DeviceState {
Unknown = 0,
Unmanaged = 10,
Unavailable = 20,
Disconnected = 30,
Prepare = 40,
Config = 50,
NeedAuth = 60,
IpConfig = 70,
IpCheck = 80,
Secondaries = 90,
Activated = 100,
Deactivating = 110,
Failed = 120
}
impl From<u32> for DeviceState {
fn from(num: u32) -> Self {
if num > 120 || num % 10 != 0 {
Self::Unknown
} else {
unsafe {
*(&num as *const u32 as *const Self)
}
}
}
}