dg_network_manager 1.0.0

Network Manager DBUS API
Documentation
use crate::dbus_api::configs::dhcp4::Dhcp4Client;
use crate::dbus_api::configs::dhcp6::Dhcp6Client;
use crate::dbus_api::configs::ipv4::Ipv4Client;
use crate::dbus_api::configs::ipv6::Ipv6Client;
use crate::dbus_api::devices::Device;
use crate::dbus_api::{ActivationStateFlags, ActiveConnectionState};
use std::io::{Error, ErrorKind};
use std::sync::Arc;
use zbus::proxy::CacheProperties;
use zbus::zvariant::OwnedObjectPath;
use zbus::{Connection, Result as ZResult, proxy};

#[proxy(
    interface = "org.freedesktop.NetworkManager.Connection.Active",
    default_service = "org.freedesktop.NetworkManager"
)]
pub trait Connection {
    #[zbus(property)]
    fn connection(&self) -> ZResult<OwnedObjectPath>;

    #[zbus(property)]
    fn specific_object(&self) -> ZResult<OwnedObjectPath>;

    #[zbus(property)]
    fn id(&self) -> ZResult<String>;

    #[zbus(property)]
    fn uuid(&self) -> ZResult<String>;

    #[zbus(property)]
    fn type_(&self) -> ZResult<String>;

    #[zbus(property)]
    fn devices(&self) -> ZResult<Vec<OwnedObjectPath>>;

    #[zbus(property)]
    fn state(&self) -> ZResult<u32>;

    #[zbus(property)]
    fn state_flags(&self) -> ZResult<u32>;

    #[zbus(property)]
    fn default(&self) -> ZResult<bool>;

    #[zbus(property)]
    fn ip4_config(&self) -> ZResult<OwnedObjectPath>;

    #[zbus(property)]
    fn dhcp4_config(&self) -> ZResult<OwnedObjectPath>;

    #[zbus(property)]
    fn default6(&self) -> ZResult<bool>;

    #[zbus(property)]
    fn ip6_config(&self) -> ZResult<OwnedObjectPath>;

    #[zbus(property)]
    fn dhcp6_config(&self) -> ZResult<OwnedObjectPath>;

    #[zbus(property)]
    fn vpn(&self) -> ZResult<bool>;

    #[zbus(property)]
    fn master(&self) -> ZResult<OwnedObjectPath>;
}

pub struct ConnectionClient {
    service_path: String,
    proxy: ConnectionProxy<'static>,
}

impl ConnectionClient {
    pub async fn new(connection: &Connection, service_path: String) -> Result<Self, Error> {
        let proxy = ConnectionProxy::builder(connection)
            .path(service_path.clone())
            .map_err(|e| Error::new(ErrorKind::InvalidInput, e.to_string()))?
            .cache_properties(CacheProperties::Yes)
            .build()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;

        // Verify we can access the connection
        proxy
            .id()
            .await
            .map_err(|e| Error::new(ErrorKind::NotFound, e.to_string()))?;

        Ok(Self {
            service_path,
            proxy,
        })
    }

    pub fn service_path(&self) -> &str {
        &self.service_path
    }

    pub async fn connection(&self) -> Result<String, Error> {
        self.proxy
            .connection()
            .await
            .map(|path| path.to_string())
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
    }

    pub async fn specific_object(&self) -> Result<String, Error> {
        self.proxy
            .specific_object()
            .await
            .map(|path| path.to_string())
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
    }

    pub async fn id(&self) -> Result<String, Error> {
        self.proxy
            .id()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
    }

    pub async fn uuid(&self) -> Result<String, Error> {
        self.proxy
            .uuid()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
    }

    pub async fn type_(&self) -> Result<String, Error> {
        self.proxy
            .type_()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
    }

    pub async fn devices(&self, connection: Arc<Connection>) -> Result<Vec<Device>, Error> {
        let device_paths = self
            .proxy
            .devices()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;

        let mut devices = Vec::new();
        for path in device_paths {
            match Device::new(connection.clone(), path.to_string()).await {
                Ok(device) => devices.push(device),
                Err(_) => continue,
            }
        }

        Ok(devices)
    }

    pub async fn state(&self) -> Result<ActiveConnectionState, Error> {
        let state = self
            .proxy
            .state()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;

        Ok(ActiveConnectionState::from(state))
    }

    pub async fn state_flags(&self) -> Result<ActivationStateFlags, Error> {
        let flags = self
            .proxy
            .state_flags()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;

        Ok(ActivationStateFlags::from(flags))
    }

    pub async fn default(&self) -> Result<bool, Error> {
        self.proxy
            .default()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
    }

    pub async fn ip4_config(&self, connection: &Connection) -> Result<Ipv4Client, Error> {
        let path = self
            .proxy
            .ip4_config()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;

        Ipv4Client::new(connection, path.to_string()).await
    }

    pub async fn dhcp4_config(&self, connection: &Connection) -> Result<Dhcp4Client, Error> {
        let path = self
            .proxy
            .dhcp4_config()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;

        Dhcp4Client::new(connection, path.to_string()).await
    }

    pub async fn default6(&self) -> Result<bool, Error> {
        self.proxy
            .default6()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
    }

    pub async fn ip6_config(&self, connection: &Connection) -> Result<Ipv6Client, Error> {
        let path = self
            .proxy
            .ip6_config()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;

        Ipv6Client::new(connection, path.to_string()).await
    }

    pub async fn dhcp6_config(&self, connection: &Connection) -> Result<Dhcp6Client, Error> {
        let path = self
            .proxy
            .dhcp6_config()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;

        Dhcp6Client::new(connection, path.to_string()).await
    }

    pub async fn vpn(&self) -> Result<bool, Error> {
        self.proxy
            .vpn()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
    }

    pub async fn master(&self, connection: Arc<Connection>) -> Result<Device, Error> {
        let path = self
            .proxy
            .master()
            .await
            .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;

        Device::new(connection, path.to_string()).await
    }
}