feat(network): improve state handling & add disconnect option
This commit is contained in:
parent
d621fb8936
commit
a5fe9e8d77
4 changed files with 173 additions and 142 deletions
|
|
@ -39,6 +39,7 @@ pub async fn handle_wireless_device(device: WirelessDevice<'_>) -> zbus::Result<
|
|||
ssid,
|
||||
strength,
|
||||
state: state,
|
||||
working: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -55,4 +56,5 @@ pub struct AccessPoint {
|
|||
pub ssid: String,
|
||||
pub strength: u8,
|
||||
pub state: DeviceState,
|
||||
pub working: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use cosmic_dbus_networkmanager::{
|
||||
active_connection::ActiveConnection,
|
||||
device::SpecificDevice,
|
||||
interface::enums::{ApFlags, ApSecurityFlags},
|
||||
interface::enums::{ActiveConnectionState, ApFlags, ApSecurityFlags},
|
||||
};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
|
|
@ -19,6 +19,10 @@ pub async fn active_connections(
|
|||
.await
|
||||
.unwrap_or_default();
|
||||
let addresses: Vec<_> = ipv4.iter().map(|d| d.address).collect();
|
||||
let state = connection
|
||||
.state()
|
||||
.await
|
||||
.unwrap_or_else(|_| ActiveConnectionState::Unknown);
|
||||
|
||||
if connection.vpn().await.unwrap_or_default() {
|
||||
info.push(ActiveConnectionInfo::Vpn {
|
||||
|
|
@ -51,6 +55,7 @@ pub async fn active_connections(
|
|||
flags: access_point.flags().await?,
|
||||
rsn_flags: access_point.rsn_flags().await?,
|
||||
wpa_flags: access_point.wpa_flags().await?,
|
||||
state,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -92,6 +97,7 @@ pub enum ActiveConnectionInfo {
|
|||
flags: ApFlags,
|
||||
rsn_flags: ApSecurityFlags,
|
||||
wpa_flags: ApSecurityFlags,
|
||||
state: ActiveConnectionState,
|
||||
},
|
||||
Vpn {
|
||||
name: String,
|
||||
|
|
|
|||
|
|
@ -5,21 +5,13 @@ use std::{collections::HashMap, fmt::Debug, hash::Hash, ops::Deref, time::Durati
|
|||
|
||||
use cosmic::iced::{self, subscription};
|
||||
use cosmic_dbus_networkmanager::{
|
||||
active_connection::ActiveConnection,
|
||||
device::SpecificDevice,
|
||||
interface::{
|
||||
active_connection::ActiveConnectionProxy, enums, enums::DeviceType,
|
||||
settings::connection::ConnectionSettingsProxy,
|
||||
},
|
||||
nm::{self, NetworkManager},
|
||||
settings::{
|
||||
connection::{ConnectionSettings, Secrets, Settings},
|
||||
NetworkManagerSettings,
|
||||
},
|
||||
interface::{active_connection::ActiveConnectionProxy, enums, enums::DeviceType},
|
||||
nm::NetworkManager,
|
||||
settings::{connection::Settings, NetworkManagerSettings},
|
||||
};
|
||||
use futures::{
|
||||
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
|
||||
future::ok,
|
||||
FutureExt, StreamExt,
|
||||
};
|
||||
use tokio::{process::Command, time::timeout};
|
||||
|
|
@ -91,6 +83,22 @@ async fn start_listening<I: Copy + Debug>(
|
|||
let (update, should_exit) = futures::select! {
|
||||
req = req => {
|
||||
match req {
|
||||
Some(NetworkManagerRequest::Disconnect(ssid)) => {
|
||||
let mut success = false;
|
||||
for c in network_manager.active_connections().await.unwrap_or_default() {
|
||||
if c.id().await.unwrap_or_default() == ssid {
|
||||
if let Ok(_) = network_manager.deactivate_connection(&c).await {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
(Some((id,
|
||||
NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::Disconnect(ssid.clone()),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
})), false)
|
||||
}
|
||||
Some(NetworkManagerRequest::SetAirplaneMode(airplane_mode)) => {
|
||||
// wifi
|
||||
let mut success = network_manager.set_wireless_enabled(!airplane_mode).await.is_ok();
|
||||
|
|
@ -103,7 +111,7 @@ async fn start_listening<I: Copy + Debug>(
|
|||
.is_ok();
|
||||
let response = NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::SetAirplaneMode(airplane_mode),
|
||||
success: true,
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
};
|
||||
(Some((id, response)), false)
|
||||
|
|
@ -256,9 +264,6 @@ async fn start_listening<I: Copy + Debug>(
|
|||
// find known connection with matching ssid and activate
|
||||
let mut status = (None, false);
|
||||
|
||||
let devices = network_manager.devices().await.ok().unwrap_or_default();
|
||||
|
||||
|
||||
for c in s.list_connections().await.unwrap_or_default() {
|
||||
let settings = match c.get_settings().await.ok() {
|
||||
Some(s) => s,
|
||||
|
|
@ -279,17 +284,15 @@ async fn start_listening<I: Copy + Debug>(
|
|||
let success = if let Ok(path) = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await {
|
||||
let dummy = ActiveConnectionProxy::new(&conn).await.unwrap();
|
||||
let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap();
|
||||
let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default());
|
||||
let s = if let enums::ActiveConnectionState::Activating = state {
|
||||
if let Ok(Some(s)) = timeout(Duration::from_secs(10), active.receive_state_changed().await.next()).await {
|
||||
s.get().await.unwrap_or_default().into()
|
||||
let mut state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default());
|
||||
while let enums::ActiveConnectionState::Activating = state {
|
||||
if let Ok(Some(s)) = timeout(Duration::from_secs(20), active.receive_state_changed().await.next()).await {
|
||||
state = s.get().await.unwrap_or_default().into();
|
||||
} else {
|
||||
state
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
state
|
||||
};
|
||||
matches!(s, enums::ActiveConnectionState::Activated)
|
||||
matches!(state, enums::ActiveConnectionState::Activated)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
|
@ -301,59 +304,6 @@ async fn start_listening<I: Copy + Debug>(
|
|||
|
||||
break;
|
||||
}
|
||||
let mut ap = None;
|
||||
|
||||
for d in &devices {
|
||||
if let Ok(Some(SpecificDevice::Wireless(wireless_device))) =
|
||||
d.downcast_to_device().await {
|
||||
for a in wireless_device.access_points().await.ok().unwrap_or_default() {
|
||||
if String::from_utf8(a.ssid().await.unwrap_or_default()).unwrap_or_default() == ssid {
|
||||
ap = Some(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if status.0.is_none() {
|
||||
|
||||
for device in network_manager.devices().await.ok().unwrap_or_default() {
|
||||
if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) {
|
||||
let conn_settings: HashMap<&str, HashMap<&str, zvariant::Value>> = HashMap::from([
|
||||
("802-11-wireless".into(), HashMap::from([
|
||||
("ssid".into(), Value::Array(ssid.as_bytes().into())),
|
||||
])),
|
||||
("connection".into(), HashMap::from([
|
||||
("id".into(), Value::Str(ssid.as_str().into())),
|
||||
("type".into(), Value::Str("802-11-wireless".into())),
|
||||
])),
|
||||
]);
|
||||
let success = if let Ok((_, path)) = network_manager.add_and_activate_connection(conn_settings, device.path(), &ap.as_ref().map(|ap| ap.path().clone()).unwrap_or_else(||ObjectPath::try_from("/").unwrap().into_owned())).await {
|
||||
let dummy = ActiveConnectionProxy::new(&conn).await.unwrap();
|
||||
let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap();
|
||||
let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default());
|
||||
let s = if let enums::ActiveConnectionState::Activating = state {
|
||||
if let Ok(Some(s)) = timeout(Duration::from_secs(10), active.receive_state_changed().await.next()).await {
|
||||
s.get().await.unwrap_or_default().into()
|
||||
} else {
|
||||
state
|
||||
}
|
||||
} else {
|
||||
state
|
||||
};
|
||||
matches!(s, enums::ActiveConnectionState::Activated)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
status = (Some((id, NetworkManagerEvent::RequestResponse {
|
||||
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()),
|
||||
success,
|
||||
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
|
||||
})), false);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if status.0.is_none() {
|
||||
status = (Some((id, NetworkManagerEvent::RequestResponse {
|
||||
|
|
@ -369,9 +319,7 @@ async fn start_listening<I: Copy + Debug>(
|
|||
}
|
||||
}}
|
||||
_ = active_conns_changed.next().boxed().fuse() => {
|
||||
let active_conns = active_connections(network_manager.active_connections().await.unwrap_or_default()).await.unwrap_or_default();
|
||||
|
||||
(Some((id, NetworkManagerEvent::ActiveConns(active_conns))), false)
|
||||
(Some((id, NetworkManagerEvent::ActiveConns(NetworkManagerState::new(&conn).await.unwrap_or_default()))), false)
|
||||
}
|
||||
_ = devices_changed.next().boxed().fuse() => {
|
||||
let devices = network_manager.devices().await.ok().unwrap_or_default();
|
||||
|
|
@ -388,11 +336,16 @@ async fn start_listening<I: Copy + Debug>(
|
|||
for f in wireless_access_point_futures {
|
||||
wireless_access_points.append(&mut f.await);
|
||||
}
|
||||
(Some((id, NetworkManagerEvent::WirelessAccessPoints(wireless_access_points))), false)
|
||||
(Some((id, NetworkManagerEvent::WirelessAccessPoints(NetworkManagerState::new(&conn).await.unwrap_or_default()))), false)
|
||||
}
|
||||
enabled = wireless_enabled_changed.next().boxed().fuse() => {
|
||||
let update = if let Some(update) = enabled {
|
||||
update.get().await.ok().map(|update| (id, NetworkManagerEvent::WiFiEnabled(update)))
|
||||
if let Ok(_) = update.get().await {
|
||||
Some((id, NetworkManagerEvent::WiFiEnabled(NetworkManagerState::new(&conn).await.unwrap_or_default())))
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -420,6 +373,7 @@ pub enum NetworkManagerRequest {
|
|||
SetAirplaneMode(bool),
|
||||
SetWiFi(bool),
|
||||
SelectAccessPoint(String),
|
||||
Disconnect(String),
|
||||
Password(String, String),
|
||||
}
|
||||
|
||||
|
|
@ -434,9 +388,9 @@ pub enum NetworkManagerEvent {
|
|||
sender: UnboundedSender<NetworkManagerRequest>,
|
||||
state: NetworkManagerState,
|
||||
},
|
||||
WiFiEnabled(bool),
|
||||
WirelessAccessPoints(Vec<AccessPoint>),
|
||||
ActiveConns(Vec<ActiveConnectionInfo>),
|
||||
WiFiEnabled(NetworkManagerState),
|
||||
WirelessAccessPoints(NetworkManagerState),
|
||||
ActiveConns(NetworkManagerState),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue