pub mod connection;
use crate::dbus_api::Options;
use crate::dbus_api::settings::connection::ConnectionSettingsClient;
use crate::utils::parse_dbus_variant;
use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::sync::Arc;
use zbus::proxy::CacheProperties;
use zbus::zvariant::{OwnedObjectPath, OwnedValue, Value};
use zbus::{Connection, Result as ZResult, proxy};
pub const NM_SETTINGS_PATH: &str = "/org/freedesktop/NetworkManager/Settings";
#[proxy(
interface = "org.freedesktop.NetworkManager.Settings",
default_service = "org.freedesktop.NetworkManager",
default_path = "/org/freedesktop/NetworkManager/Settings"
)]
pub trait Settings {
fn list_connections(&self) -> ZResult<Vec<OwnedObjectPath>>;
fn get_connection_by_uuid(&self, uuid: &str) -> ZResult<OwnedObjectPath>;
fn add_connection(
&self,
connection: HashMap<&str, HashMap<&str, Value<'_>>>,
) -> ZResult<OwnedObjectPath>;
fn add_connection_unsaved(
&self,
connection: HashMap<&str, HashMap<&str, Value<'_>>>,
) -> ZResult<OwnedObjectPath>;
fn add_connection2(
&self,
settings: HashMap<&str, HashMap<&str, Value<'_>>>,
flags: u32,
args: HashMap<&str, Value<'_>>,
) -> ZResult<(OwnedObjectPath, HashMap<String, OwnedValue>)>;
fn load_connections(&self, filenames: Vec<&str>) -> ZResult<(bool, Vec<String>)>;
fn reload_connections(&self) -> ZResult<bool>;
fn save_hostname(&self, hostname: &str) -> ZResult<()>;
#[zbus(property)]
fn connections(&self) -> ZResult<Vec<OwnedObjectPath>>;
#[zbus(property)]
fn hostname(&self) -> ZResult<String>;
#[zbus(property)]
fn can_modify(&self) -> ZResult<bool>;
}
pub struct SettingsClient {
service_path: String,
proxy: SettingsProxy<'static>,
connection: Arc<Connection>,
}
impl SettingsClient {
pub async fn new(connection: Arc<Connection>, service_path: String) -> Result<Self, Error> {
let proxy = SettingsProxy::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()))?;
Ok(Self {
service_path,
proxy,
connection,
})
}
pub fn service_path(&self) -> &str {
&self.service_path
}
pub async fn list_connections(&self) -> Result<Vec<ConnectionSettingsClient>, Error> {
let paths = self
.proxy
.list_connections()
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?;
let mut connections = Vec::new();
for path in paths {
match ConnectionSettingsClient::new(self.connection.clone(), path.to_string()).await {
Ok(conn) => connections.push(conn),
Err(_) => continue,
}
}
Ok(connections)
}
pub async fn get_connection_by_uuid(&self, uuid: &str) -> Result<OwnedObjectPath, Error> {
self.proxy
.get_connection_by_uuid(uuid)
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn add_connection(
&self,
connection: HashMap<&str, HashMap<&str, Value<'_>>>,
) -> Result<OwnedObjectPath, Error> {
self.proxy
.add_connection(connection)
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn add_connection_unsaved(
&self,
connection: HashMap<&str, HashMap<&str, Value<'_>>>,
) -> Result<OwnedObjectPath, Error> {
self.proxy
.add_connection_unsaved(connection)
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn add_connection2(
&self,
settings: HashMap<&str, HashMap<&str, Value<'_>>>,
flags: u32,
args: HashMap<&str, Value<'_>>,
) -> Result<(OwnedObjectPath, Options), Error> {
self.proxy
.add_connection2(settings, flags, args)
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn load_connections(
&self,
filenames: Vec<&str>,
) -> Result<(bool, Vec<String>), Error> {
self.proxy
.load_connections(filenames)
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn reload_connections(&self) -> Result<bool, Error> {
self.proxy
.reload_connections()
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn save_hostname(&self, hostname: &str) -> Result<(), Error> {
self.proxy
.save_hostname(hostname)
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn connections(&self) -> Result<Vec<OwnedObjectPath>, Error> {
self.proxy
.connections()
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn hostname(&self) -> Result<String, Error> {
self.proxy
.hostname()
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn can_modify(&self) -> Result<bool, Error> {
self.proxy
.can_modify()
.await
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
}
pub async fn find_connection_by_id(
&self,
id: &str,
) -> Result<Option<ConnectionSettingsClient>, Error> {
let connections = self.list_connections().await?;
for conn in connections {
let settings = conn.get_settings().await?;
if let Some(connection_settings) = settings.get("connection") {
if let Some(conn_id) = connection_settings.get("id").cloned() {
if id == parse_dbus_variant(conn_id.into()) {
return Ok(Some(conn));
}
}
}
}
Ok(None)
}
}