refactor: simplify state updates from network manager subscription
This commit is contained in:
parent
c10087a55d
commit
833e68d63b
3 changed files with 230 additions and 174 deletions
|
|
@ -15,10 +15,11 @@ futures = "0.3"
|
||||||
zbus = { version = "3.7", no-default-features = true }
|
zbus = { version = "3.7", no-default-features = true }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.4"
|
pretty_env_logger = "0.4"
|
||||||
|
itertools = "0.10.3"
|
||||||
|
slotmap = "1.0.6"
|
||||||
|
tokio = { version = "1.15.0", features = ["full"] }
|
||||||
|
anyhow = "1.0"
|
||||||
# Application i18n
|
# Application i18n
|
||||||
i18n-embed = { version = "0.13.4", features = ["fluent-system", "desktop-requester"] }
|
i18n-embed = { version = "0.13.4", features = ["fluent-system", "desktop-requester"] }
|
||||||
i18n-embed-fl = "0.6.4"
|
i18n-embed-fl = "0.6.4"
|
||||||
rust-embed = "6.3.0"
|
rust-embed = "6.3.0"
|
||||||
itertools = "0.10.3"
|
|
||||||
slotmap = "1.0.6"
|
|
||||||
tokio = { version = "1.15.0", features = ["full"] }
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use cosmic::iced_style;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
applet::CosmicAppletHelper,
|
applet::CosmicAppletHelper,
|
||||||
iced::{
|
iced::{
|
||||||
|
|
@ -20,19 +21,10 @@ use cosmic::{
|
||||||
widget::{button, horizontal_rule, icon, list_column, toggler},
|
widget::{button, horizontal_rule, icon, list_column, toggler},
|
||||||
Element, Theme,
|
Element, Theme,
|
||||||
};
|
};
|
||||||
use cosmic::{
|
|
||||||
iced_style,
|
|
||||||
widget::segmented_button::{
|
|
||||||
self,
|
|
||||||
cosmic::{
|
|
||||||
horizontal_segmented_selection, horizontal_view_switcher, vertical_segmented_selection,
|
|
||||||
vertical_view_switcher,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use cosmic_dbus_networkmanager::{access_point, interface::enums::DeviceState};
|
use cosmic_dbus_networkmanager::{access_point, interface::enums::DeviceState};
|
||||||
use futures::channel::mpsc::UnboundedSender;
|
use futures::channel::mpsc::UnboundedSender;
|
||||||
|
|
||||||
|
use crate::network_manager::NetworkManagerState;
|
||||||
use crate::{
|
use crate::{
|
||||||
config, fl,
|
config, fl,
|
||||||
network_manager::{
|
network_manager::{
|
||||||
|
|
@ -174,7 +166,9 @@ impl Application for CosmicNetworkApplet {
|
||||||
Message::Ignore => {}
|
Message::Ignore => {}
|
||||||
Message::ToggleAirplaneMode(enabled) => {
|
Message::ToggleAirplaneMode(enabled) => {
|
||||||
self.airplane_mode = enabled;
|
self.airplane_mode = enabled;
|
||||||
// TODO apply changes
|
if let Some(tx) = self.nm_sender.as_mut() {
|
||||||
|
let _ = tx.unbounded_send(NetworkManagerRequest::SetAirplaneMode(enabled));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Message::ToggleWiFi(enabled) => {
|
Message::ToggleWiFi(enabled) => {
|
||||||
self.wifi = enabled;
|
self.wifi = enabled;
|
||||||
|
|
@ -185,11 +179,14 @@ impl Application for CosmicNetworkApplet {
|
||||||
Message::NetworkManagerEvent(event) => match event {
|
Message::NetworkManagerEvent(event) => match event {
|
||||||
NetworkManagerEvent::Init {
|
NetworkManagerEvent::Init {
|
||||||
sender,
|
sender,
|
||||||
wireless_access_points,
|
state:
|
||||||
active_conns,
|
NetworkManagerState {
|
||||||
known_access_points,
|
wireless_access_points,
|
||||||
wifi_enabled,
|
active_conns,
|
||||||
airplane_mode,
|
known_access_points,
|
||||||
|
wifi_enabled,
|
||||||
|
airplane_mode,
|
||||||
|
},
|
||||||
} => {
|
} => {
|
||||||
self.nm_sender.replace(sender);
|
self.nm_sender.replace(sender);
|
||||||
self.wireless_access_points = wireless_access_points;
|
self.wireless_access_points = wireless_access_points;
|
||||||
|
|
@ -210,16 +207,22 @@ impl Application for CosmicNetworkApplet {
|
||||||
self.update_icon_name();
|
self.update_icon_name();
|
||||||
}
|
}
|
||||||
NetworkManagerEvent::RequestResponse {
|
NetworkManagerEvent::RequestResponse {
|
||||||
wireless_access_points,
|
state:
|
||||||
active_conns,
|
NetworkManagerState {
|
||||||
wifi_enabled,
|
wireless_access_points,
|
||||||
|
active_conns,
|
||||||
|
known_access_points,
|
||||||
|
wifi_enabled,
|
||||||
|
airplane_mode,
|
||||||
|
},
|
||||||
success,
|
success,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if success {
|
if success {
|
||||||
self.wireless_access_points = wireless_access_points;
|
self.wireless_access_points = wireless_access_points;
|
||||||
self.active_conns = active_conns;
|
self.active_conns = active_conns;
|
||||||
|
self.known_access_points = known_access_points;
|
||||||
|
self.airplane_mode = airplane_mode;
|
||||||
self.wifi = wifi_enabled;
|
self.wifi = wifi_enabled;
|
||||||
self.update_icon_name();
|
self.update_icon_name();
|
||||||
}
|
}
|
||||||
|
|
@ -243,19 +246,27 @@ impl Application for CosmicNetworkApplet {
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Message::SubmitPassword => {
|
Message::SubmitPassword => {
|
||||||
// TODO setup connection
|
// save password
|
||||||
|
let tx = if let Some(tx) = self.nm_sender.as_ref() {
|
||||||
|
tx
|
||||||
|
} else {
|
||||||
|
return Command::none();
|
||||||
|
};
|
||||||
|
|
||||||
match self.new_connection.take() {
|
match self.new_connection.take() {
|
||||||
Some(new_connection) => {
|
Some(NewConnectionState::EnterPassword {
|
||||||
let ap: AccessPoint = new_connection.into();
|
password,
|
||||||
if let Some(tx) = self.nm_sender.as_ref() {
|
access_point,
|
||||||
let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint(
|
}) => {
|
||||||
ap.ssid.clone(),
|
let _ = tx.unbounded_send(NetworkManagerRequest::Password(
|
||||||
));
|
access_point.ssid.clone(),
|
||||||
}
|
password.to_string(),
|
||||||
self.new_connection.replace(NewConnectionState::Failure(ap));
|
));
|
||||||
|
self.new_connection
|
||||||
|
.replace(NewConnectionState::Failure(access_point.clone()));
|
||||||
}
|
}
|
||||||
None => {}
|
_ => {}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
Message::ActivateKnownWifi(ssid) => {}
|
Message::ActivateKnownWifi(ssid) => {}
|
||||||
Message::CancelNewConnection => {
|
Message::CancelNewConnection => {
|
||||||
|
|
@ -386,7 +397,7 @@ impl Application for CosmicNetworkApplet {
|
||||||
.padding([8, 24])
|
.padding([8, 24])
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.style(button_style.clone());
|
.style(button_style.clone());
|
||||||
let btn = match known.state {
|
btn = match known.state {
|
||||||
// DeviceState::Prepare => todo!(),
|
// DeviceState::Prepare => todo!(),
|
||||||
// DeviceState::Config => todo!(),
|
// DeviceState::Config => todo!(),
|
||||||
// DeviceState::NeedAuth => todo!(),
|
// DeviceState::NeedAuth => todo!(),
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
pub mod available_wifi;
|
pub mod available_wifi;
|
||||||
pub mod current_networks;
|
pub mod current_networks;
|
||||||
|
|
||||||
use std::{fmt::Debug, hash::Hash, time::Duration};
|
use std::{collections::HashMap, fmt::Debug, hash::Hash, time::Duration};
|
||||||
|
|
||||||
use cosmic::iced::{self, subscription};
|
use cosmic::iced::{self, subscription};
|
||||||
use cosmic_dbus_networkmanager::{
|
use cosmic_dbus_networkmanager::{
|
||||||
device::SpecificDevice,
|
device::SpecificDevice,
|
||||||
interface::{enums::DeviceType, settings::connection::ConnectionSettingsProxy},
|
interface::{enums::DeviceType, settings::connection::ConnectionSettingsProxy},
|
||||||
nm::NetworkManager,
|
nm::{self, NetworkManager},
|
||||||
settings::{
|
settings::{
|
||||||
connection::{ConnectionSettings, Secrets, Settings},
|
connection::{ConnectionSettings, Secrets, Settings},
|
||||||
NetworkManagerSettings,
|
NetworkManagerSettings,
|
||||||
|
|
@ -18,7 +18,11 @@ use futures::{
|
||||||
future::ok,
|
future::ok,
|
||||||
FutureExt, StreamExt,
|
FutureExt, StreamExt,
|
||||||
};
|
};
|
||||||
use zbus::Connection;
|
use tokio::process::Command;
|
||||||
|
use zbus::{
|
||||||
|
zvariant::{self, Value},
|
||||||
|
Connection,
|
||||||
|
};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
available_wifi::{handle_wireless_device, AccessPoint},
|
available_wifi::{handle_wireless_device, AccessPoint},
|
||||||
|
|
@ -52,88 +56,15 @@ async fn start_listening<I: Copy>(
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(_) => return (None, State::Finished),
|
Err(_) => return (None, State::Finished),
|
||||||
};
|
};
|
||||||
let network_manager = match NetworkManager::new(&conn).await {
|
|
||||||
Ok(n) => n,
|
|
||||||
Err(_) => return (None, State::Finished),
|
|
||||||
};
|
|
||||||
let s = match NetworkManagerSettings::new(&conn).await {
|
|
||||||
Ok(s) => s,
|
|
||||||
Err(_) => return (None, State::Finished),
|
|
||||||
};
|
|
||||||
let known_conns = s.list_connections().await.unwrap_or_default();
|
|
||||||
|
|
||||||
let (tx, rx) = unbounded();
|
let (tx, rx) = unbounded();
|
||||||
let mut active_conns = active_connections(
|
let nm_state = NetworkManagerState::new(&conn).await.unwrap_or_default();
|
||||||
network_manager
|
|
||||||
.active_connections()
|
|
||||||
.await
|
|
||||||
.unwrap_or_default(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap_or_default();
|
|
||||||
active_conns.sort_by(|a, b| {
|
|
||||||
let helper = |conn: &ActiveConnectionInfo| match conn {
|
|
||||||
ActiveConnectionInfo::Vpn { name, .. } => format!("0{name}"),
|
|
||||||
ActiveConnectionInfo::Wired { name, .. } => format!("1{name}"),
|
|
||||||
ActiveConnectionInfo::WiFi { name, .. } => format!("2{name}"),
|
|
||||||
};
|
|
||||||
helper(a).cmp(&helper(b))
|
|
||||||
});
|
|
||||||
let wifi_enabled = network_manager.wireless_enabled().await.unwrap_or_default();
|
|
||||||
let devices = network_manager.devices().await.ok().unwrap_or_default();
|
|
||||||
let wireless_access_point_futures: Vec<_> = devices
|
|
||||||
.into_iter()
|
|
||||||
.map(|device| async move {
|
|
||||||
if let Ok(Some(SpecificDevice::Wireless(wireless_device))) =
|
|
||||||
device.downcast_to_device().await
|
|
||||||
{
|
|
||||||
handle_wireless_device(wireless_device)
|
|
||||||
.await
|
|
||||||
.unwrap_or_default()
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let mut wireless_access_points =
|
|
||||||
Vec::with_capacity(wireless_access_point_futures.len());
|
|
||||||
for f in wireless_access_point_futures {
|
|
||||||
let mut access_points = f.await;
|
|
||||||
wireless_access_points.append(&mut access_points);
|
|
||||||
}
|
|
||||||
let mut known_ssid = Vec::with_capacity(known_conns.len());
|
|
||||||
for c in known_conns {
|
|
||||||
let s = c.get_settings().await.unwrap();
|
|
||||||
let s = Settings::new(s);
|
|
||||||
if let Some(cur_ssid) = s
|
|
||||||
.wifi
|
|
||||||
.clone()
|
|
||||||
.and_then(|w| w.ssid)
|
|
||||||
.and_then(|ssid| String::from_utf8(ssid).ok())
|
|
||||||
{
|
|
||||||
known_ssid.push(cur_ssid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let known_access_points: Vec<_> = wireless_access_points
|
|
||||||
.iter()
|
|
||||||
.filter(|a| {
|
|
||||||
known_ssid.contains(&a.ssid)
|
|
||||||
&& !active_conns.iter().any(|ac| ac.name() == a.ssid)
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
wireless_access_points.sort_by(|a, b| b.strength.cmp(&a.strength));
|
|
||||||
drop(network_manager);
|
|
||||||
return (
|
return (
|
||||||
Some((
|
Some((
|
||||||
id,
|
id,
|
||||||
NetworkManagerEvent::Init {
|
NetworkManagerEvent::Init {
|
||||||
sender: tx,
|
sender: tx,
|
||||||
wireless_access_points,
|
state: nm_state,
|
||||||
wifi_enabled,
|
|
||||||
airplane_mode: false,
|
|
||||||
known_access_points,
|
|
||||||
active_conns,
|
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
State::Waiting(conn, rx),
|
State::Waiting(conn, rx),
|
||||||
|
|
@ -156,63 +87,83 @@ async fn start_listening<I: Copy>(
|
||||||
let (update, should_exit) = futures::select! {
|
let (update, should_exit) = futures::select! {
|
||||||
req = req => {
|
req = req => {
|
||||||
match req {
|
match req {
|
||||||
Some(NetworkManagerRequest::SetAirplaneMode(state)) => {
|
Some(NetworkManagerRequest::SetAirplaneMode(airplane_mode)) => {
|
||||||
// TODO set airplane mode
|
// wifi
|
||||||
let _ = network_manager.set_wireless_enabled(state).await;
|
let mut success = network_manager.set_wireless_enabled(!airplane_mode).await.is_ok();
|
||||||
(None, false)
|
// bluetooth
|
||||||
|
success = success && Command::new("rfkill")
|
||||||
|
.arg(if airplane_mode { "block" } else { "unblock" })
|
||||||
|
.arg("bluetooth")
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
.is_ok();
|
||||||
|
let response = NetworkManagerEvent::RequestResponse {
|
||||||
|
req: NetworkManagerRequest::SetAirplaneMode(airplane_mode),
|
||||||
|
success: true,
|
||||||
|
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||||
|
};
|
||||||
|
(Some((id, response)), false)
|
||||||
}
|
}
|
||||||
Some(NetworkManagerRequest::SetWiFi(enabled)) => {
|
Some(NetworkManagerRequest::SetWiFi(enabled)) => {
|
||||||
let success = network_manager.set_wireless_enabled(enabled).await.is_ok();
|
let success = network_manager.set_wireless_enabled(enabled).await.is_ok();
|
||||||
let active_conns = active_connections(network_manager.active_connections().await.unwrap_or_default()).await.unwrap_or_default();
|
let response = NetworkManagerEvent::RequestResponse {
|
||||||
let devices = network_manager.devices().await.ok().unwrap_or_default();
|
req: NetworkManagerRequest::SetAirplaneMode(enabled),
|
||||||
let wireless_access_point_futures: Vec<_> = devices.into_iter().map(|device| async move {
|
|
||||||
if let Ok(Some(SpecificDevice::Wireless(wireless_device))) =
|
|
||||||
device.downcast_to_device().await
|
|
||||||
{
|
|
||||||
handle_wireless_device(wireless_device).await.unwrap_or_default()
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}).collect();
|
|
||||||
let mut wireless_access_points = Vec::with_capacity(wireless_access_point_futures.len());
|
|
||||||
for f in wireless_access_point_futures {
|
|
||||||
wireless_access_points.append(&mut f.await);
|
|
||||||
}
|
|
||||||
(Some((id, NetworkManagerEvent::RequestResponse {
|
|
||||||
req: NetworkManagerRequest::SetWiFi(enabled),
|
|
||||||
success,
|
success,
|
||||||
active_conns,
|
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||||
wireless_access_points,
|
};
|
||||||
wifi_enabled: enabled,
|
(Some((id, response)), false)
|
||||||
airplane_mode: false,
|
}
|
||||||
})), false)
|
Some(NetworkManagerRequest::Password(ssid, password)) => {
|
||||||
|
let s = match NetworkManagerSettings::new(&conn).await {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => return (None, State::Finished),
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO more convenient methods of managing settings
|
||||||
|
for c in s.list_connections().await.unwrap_or_default() {
|
||||||
|
let mut settings = match c.get_settings().await.ok() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
dbg!(&settings);
|
||||||
|
let cur_ssid = settings
|
||||||
|
.get("802-11-wireless")
|
||||||
|
.and_then(|w| w.get("ssid"))
|
||||||
|
.cloned()
|
||||||
|
.and_then(|ssid| ssid.try_into().ok())
|
||||||
|
.and_then(|ssid| String::from_utf8(ssid).ok());
|
||||||
|
dbg!(&cur_ssid);
|
||||||
|
if cur_ssid.as_ref() != Some(&ssid) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut secrets = match
|
||||||
|
c.get_secrets("802-11-wireless-security")
|
||||||
|
.await {
|
||||||
|
Ok(s) => s,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
if let Some(s) = secrets.get_mut("802-11-wireless-security") {
|
||||||
|
s.insert("psk".into(), Value::Str(password.into()).to_owned());
|
||||||
|
drop(s);
|
||||||
|
settings.extend(secrets.into_iter());
|
||||||
|
let settings: HashMap<_, _> = settings.iter().map(|(k, v)| {
|
||||||
|
let map = (k.as_str(), v.iter()
|
||||||
|
.map(|(k, v)| (k.as_str(), v.into()))
|
||||||
|
.collect::<HashMap<_, _>>());
|
||||||
|
map
|
||||||
|
}).collect();
|
||||||
|
dbg!(settings.clone());
|
||||||
|
dbg!(c.update(settings).await);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(None, false)
|
||||||
}
|
}
|
||||||
Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => {
|
Some(NetworkManagerRequest::SelectAccessPoint(ssid)) => {
|
||||||
'device_loop: for device in network_manager.devices().await.ok().unwrap_or_default() {
|
'device_loop: for device in network_manager.devices().await.ok().unwrap_or_default() {
|
||||||
if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) {
|
if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) {
|
||||||
let connection_settings = NetworkManagerSettings::new(&conn).await.unwrap();
|
|
||||||
for conn in connection_settings.list_connections().await.unwrap() {
|
|
||||||
let s = conn.get_settings().await.unwrap();
|
|
||||||
let s = Settings::new(s);
|
|
||||||
|
|
||||||
let cur_ssid = s
|
|
||||||
.wifi
|
|
||||||
.clone()
|
|
||||||
.and_then(|w| w.ssid)
|
|
||||||
.and_then(|ssid| String::from_utf8(ssid).ok());
|
|
||||||
if cur_ssid.as_ref() == Some(&ssid) {
|
|
||||||
// dbg!(s);
|
|
||||||
// dbg!(conn.get_secrets("connection").await);
|
|
||||||
// dbg!(Secrets::new(&conn).await);
|
|
||||||
// dbg!(psk);
|
|
||||||
// connection update can be used to set password
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for conn in device.available_connections().await.unwrap_or_default() {
|
|
||||||
// network_manager.activate_connection(conn, device.clone());
|
|
||||||
// dbg!(&conn.path());
|
|
||||||
// TODO activate connection
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(None, false)
|
(None, false)
|
||||||
|
|
@ -273,27 +224,120 @@ pub enum NetworkManagerRequest {
|
||||||
SetAirplaneMode(bool),
|
SetAirplaneMode(bool),
|
||||||
SetWiFi(bool),
|
SetWiFi(bool),
|
||||||
SelectAccessPoint(String),
|
SelectAccessPoint(String),
|
||||||
|
Password(String, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum NetworkManagerEvent {
|
pub enum NetworkManagerEvent {
|
||||||
Init {
|
|
||||||
sender: UnboundedSender<NetworkManagerRequest>,
|
|
||||||
wireless_access_points: Vec<AccessPoint>,
|
|
||||||
active_conns: Vec<ActiveConnectionInfo>,
|
|
||||||
known_access_points: Vec<AccessPoint>,
|
|
||||||
wifi_enabled: bool,
|
|
||||||
airplane_mode: bool,
|
|
||||||
},
|
|
||||||
RequestResponse {
|
RequestResponse {
|
||||||
req: NetworkManagerRequest,
|
req: NetworkManagerRequest,
|
||||||
wireless_access_points: Vec<AccessPoint>,
|
state: NetworkManagerState,
|
||||||
active_conns: Vec<ActiveConnectionInfo>,
|
|
||||||
wifi_enabled: bool,
|
|
||||||
airplane_mode: bool,
|
|
||||||
success: bool,
|
success: bool,
|
||||||
},
|
},
|
||||||
|
Init {
|
||||||
|
sender: UnboundedSender<NetworkManagerRequest>,
|
||||||
|
state: NetworkManagerState,
|
||||||
|
},
|
||||||
WiFiEnabled(bool),
|
WiFiEnabled(bool),
|
||||||
WirelessAccessPoints(Vec<AccessPoint>),
|
WirelessAccessPoints(Vec<AccessPoint>),
|
||||||
ActiveConns(Vec<ActiveConnectionInfo>),
|
ActiveConns(Vec<ActiveConnectionInfo>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct NetworkManagerState {
|
||||||
|
pub wireless_access_points: Vec<AccessPoint>,
|
||||||
|
pub active_conns: Vec<ActiveConnectionInfo>,
|
||||||
|
pub known_access_points: Vec<AccessPoint>,
|
||||||
|
pub wifi_enabled: bool,
|
||||||
|
pub airplane_mode: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetworkManagerState {
|
||||||
|
pub async fn new(conn: &Connection) -> anyhow::Result<Self> {
|
||||||
|
let network_manager = NetworkManager::new(&conn).await?;
|
||||||
|
let mut _self = Self::default();
|
||||||
|
|
||||||
|
// airplane mode
|
||||||
|
let airplaine_mode = Command::new("rfkill")
|
||||||
|
.arg("list")
|
||||||
|
.arg("bluetooth")
|
||||||
|
.output()
|
||||||
|
.await?;
|
||||||
|
let airplane_mode = std::str::from_utf8(&airplaine_mode.stdout).unwrap_or_default();
|
||||||
|
let bluetooth_disabled = airplane_mode.contains("Soft blocked: yes");
|
||||||
|
|
||||||
|
if !network_manager.wireless_enabled().await.unwrap_or_default() {
|
||||||
|
_self.airplane_mode = bluetooth_disabled;
|
||||||
|
return Ok(_self);
|
||||||
|
} else {
|
||||||
|
_self.wifi_enabled = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
let s = NetworkManagerSettings::new(&conn).await?;
|
||||||
|
|
||||||
|
let known_conns = s.list_connections().await.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut active_conns = active_connections(
|
||||||
|
network_manager
|
||||||
|
.active_connections()
|
||||||
|
.await
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default();
|
||||||
|
active_conns.sort_by(|a, b| {
|
||||||
|
let helper = |conn: &ActiveConnectionInfo| match conn {
|
||||||
|
ActiveConnectionInfo::Vpn { name, .. } => format!("0{name}"),
|
||||||
|
ActiveConnectionInfo::Wired { name, .. } => format!("1{name}"),
|
||||||
|
ActiveConnectionInfo::WiFi { name, .. } => format!("2{name}"),
|
||||||
|
};
|
||||||
|
helper(a).cmp(&helper(b))
|
||||||
|
});
|
||||||
|
let devices = network_manager.devices().await.ok().unwrap_or_default();
|
||||||
|
let wireless_access_point_futures: Vec<_> = devices
|
||||||
|
.into_iter()
|
||||||
|
.map(|device| async move {
|
||||||
|
if let Ok(Some(SpecificDevice::Wireless(wireless_device))) =
|
||||||
|
device.downcast_to_device().await
|
||||||
|
{
|
||||||
|
handle_wireless_device(wireless_device)
|
||||||
|
.await
|
||||||
|
.unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut wireless_access_points = Vec::with_capacity(wireless_access_point_futures.len());
|
||||||
|
for f in wireless_access_point_futures {
|
||||||
|
let mut access_points = f.await;
|
||||||
|
wireless_access_points.append(&mut access_points);
|
||||||
|
}
|
||||||
|
let mut known_ssid = Vec::with_capacity(known_conns.len());
|
||||||
|
for c in known_conns {
|
||||||
|
let s = c.get_settings().await.unwrap();
|
||||||
|
let s = Settings::new(s);
|
||||||
|
if let Some(cur_ssid) = s
|
||||||
|
.wifi
|
||||||
|
.clone()
|
||||||
|
.and_then(|w| w.ssid)
|
||||||
|
.and_then(|ssid| String::from_utf8(ssid).ok())
|
||||||
|
{
|
||||||
|
known_ssid.push(cur_ssid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let known_access_points: Vec<_> = wireless_access_points
|
||||||
|
.iter()
|
||||||
|
.filter(|a| {
|
||||||
|
known_ssid.contains(&a.ssid) && !active_conns.iter().any(|ac| ac.name() == a.ssid)
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
wireless_access_points.sort_by(|a, b| b.strength.cmp(&a.strength));
|
||||||
|
|
||||||
|
_self.wireless_access_points = wireless_access_points;
|
||||||
|
_self.active_conns = active_conns;
|
||||||
|
_self.known_access_points = known_access_points;
|
||||||
|
Ok(_self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue