librefi_rs/src/connectors/networkmanager.rs

96 lines
3.6 KiB
Rust

use crate::connectors::types::{
Connects, ListsNetworkInterfaces, ListsNetworks, Network, NetworkInterface,
};
use crate::connectors::utils::call_exec;
use std::borrow::BorrowMut;
use std::str::Split;
pub struct NetworkManagerConnector {}
impl NetworkManagerConnector {
fn call_nmcli(&self, add_args: Vec<&str>) -> Result<Vec<u8>, String> {
let args = vec!["-t", "-m", "tabular", "-c", "no", "-o", "-e", "yes"]
.into_iter()
.chain(add_args.into_iter())
.collect();
call_exec("networkmanager", "nmcli", args)
}
fn get_nmcli(&self, add_args: Vec<&str>) -> Result<Vec<Vec<String>>, String> {
let output = self
.call_nmcli(add_args)
.expect("calling networkmanager failed");
let res = String::from_utf8(output).expect("networkmanager returned non-utf8");
let lines: Vec<&str> = res.split("\n").filter(|ln| !ln.is_empty()).collect();
let lines_with_fields: Vec<Split<&str>> = lines.into_iter().map(|line| line.split(":")).collect();
let mut parsed: Vec<Vec<String>> = vec![];
for old_fields_immut in lines_with_fields.clone() {
let mut old_fields = old_fields_immut;
let mut new_fields: Vec<String> = vec![];
let mut continuation = false;
loop {
match old_fields.next() {
Some(field) => {
let mut new_field = match continuation {
true => new_fields.pop().expect("new field").to_string(),
false => "".to_string(),
};
if continuation {
new_field.push(':');
}
new_field.push_str(match field.strip_suffix("\\") {
Some(stripped) => stripped,
None => field,
});
new_fields.push(new_field);
continuation = field.ends_with("\\");
},
None => {
let parsed_line = new_fields;
parsed.push(parsed_line);
break
},
}
}
}
Ok(parsed)
}
}
impl ListsNetworkInterfaces for NetworkManagerConnector {
fn list_network_interfaces(&self) -> Result<Vec<NetworkInterface>, String> {
let iface_list = match self.get_nmcli(
vec!["-f", "DEVICE,TYPE,STATE,CONNECTION", "device"],
) {
Ok(list) => list,
Err(err) => return Err(err),
};
let ifaces = iface_list.into_iter().map(|ifa| NetworkInterface {
machine_name: ifa[0].clone(),
enabled: ifa[2] != "unavailable",
..Default::default()
}).collect();
Ok(ifaces)
}
}
impl ListsNetworks for NetworkManagerConnector {
fn list_networks(&self, iface: &NetworkInterface) -> Result<Vec<Network>, String> {
let net_list = match self.get_nmcli(vec![
"-f", "SSID,BSSID,CHAN,SIGNAL,WPA-FLAGS,IN-USE",
"device", "wifi", "list", "ifname", &iface.machine_name],
) {
Ok(list) => list,
Err(err) => return Err(err),
};
let nets = net_list.into_iter().map(|net| Network {
ssid: net[0].to_string(),
bssid: Some(net[1].to_string()),
channel: Some(net[2].parse::<u8>().unwrap()),
rssi: Some(net[3].parse::<i8>().unwrap()),
..Default::default()
}).collect();
Ok(nets)
}
}