wip: handle state after activating connections

This commit is contained in:
Ashley Wulber 2023-01-09 22:43:35 -05:00
parent cdca1d96ac
commit 6b5ce0f35f
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820
3 changed files with 184 additions and 34 deletions

View file

@ -38,6 +38,7 @@ pub fn run() -> cosmic::iced::Result {
CosmicNetworkApplet::run(helper.window_settings()) CosmicNetworkApplet::run(helper.window_settings())
} }
#[derive(Debug)]
enum NewConnectionState { enum NewConnectionState {
EnterPassword { EnterPassword {
access_point: AccessPoint, access_point: AccessPoint,
@ -216,19 +217,61 @@ impl Application for CosmicNetworkApplet {
airplane_mode, airplane_mode,
}, },
success, success,
.. req,
} => { } => {
if success { if success {
match req {
NetworkManagerRequest::SetAirplaneMode(_)
| NetworkManagerRequest::SetWiFi(_) => {}
NetworkManagerRequest::SelectAccessPoint(_)
| NetworkManagerRequest::Password(_, _) => {
self.new_connection.take();
self.show_visible_networks = false;
}
}
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.known_access_points = known_access_points;
self.airplane_mode = airplane_mode; self.airplane_mode = airplane_mode;
self.wifi = wifi_enabled; self.wifi = wifi_enabled;
self.update_icon_name(); self.update_icon_name();
} else {
match req {
NetworkManagerRequest::SetAirplaneMode(_)
| NetworkManagerRequest::SetWiFi(_) => {}
NetworkManagerRequest::SelectAccessPoint(_) => {
if let Some(NewConnectionState::Waiting(access_point)) =
self.new_connection.as_ref()
{
self.new_connection
.replace(NewConnectionState::Failure(access_point.clone()));
}
}
NetworkManagerRequest::Password(_, _) => {
if let Some(NewConnectionState::EnterPassword {
access_point,
..
}) = self.new_connection.as_ref()
{
self.new_connection
.replace(NewConnectionState::Failure(access_point.clone()));
}
}
}
} }
} }
}, },
Message::SelectWirelessAccessPoint(access_point) => { Message::SelectWirelessAccessPoint(access_point) => {
let tx = if let Some(tx) = self.nm_sender.as_ref() {
tx
} else {
return Command::none();
};
let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint(
access_point.ssid.clone(),
));
self.new_connection self.new_connection
.replace(NewConnectionState::EnterPassword { .replace(NewConnectionState::EnterPassword {
access_point, access_point,
@ -263,12 +306,19 @@ impl Application for CosmicNetworkApplet {
password.to_string(), password.to_string(),
)); ));
self.new_connection self.new_connection
.replace(NewConnectionState::Failure(access_point.clone())); .replace(NewConnectionState::Waiting(access_point.clone()));
} }
_ => {} _ => {}
}; };
} }
Message::ActivateKnownWifi(ssid) => {} Message::ActivateKnownWifi(ssid) => {
let tx = if let Some(tx) = self.nm_sender.as_ref() {
tx
} else {
return Command::none();
};
let _ = tx.unbounded_send(NetworkManagerRequest::SelectAccessPoint(ssid));
}
Message::CancelNewConnection => { Message::CancelNewConnection => {
self.new_connection.take(); self.new_connection.take();
} }

View file

@ -28,7 +28,6 @@ pub async fn handle_wireless_device(device: WirelessDevice<'_>) -> zbus::Result<
for ap in access_points { for ap in access_points {
let ssid = String::from_utf8_lossy(&ap.ssid().await?.clone()).into_owned(); let ssid = String::from_utf8_lossy(&ap.ssid().await?.clone()).into_owned();
let strength = ap.strength().await?; let strength = ap.strength().await?;
if let Some(access_point) = aps.get(&ssid) { if let Some(access_point) = aps.get(&ssid) {
if access_point.strength > strength { if access_point.strength > strength {
continue; continue;

View file

@ -5,8 +5,12 @@ use std::{collections::HashMap, fmt::Debug, hash::Hash, ops::Deref, time::Durati
use cosmic::iced::{self, subscription}; use cosmic::iced::{self, subscription};
use cosmic_dbus_networkmanager::{ use cosmic_dbus_networkmanager::{
active_connection::ActiveConnection,
device::SpecificDevice, device::SpecificDevice,
interface::{enums::DeviceType, settings::connection::ConnectionSettingsProxy}, interface::{
active_connection::ActiveConnectionProxy, enums, enums::DeviceType,
settings::connection::ConnectionSettingsProxy,
},
nm::{self, NetworkManager}, nm::{self, NetworkManager},
settings::{ settings::{
connection::{ConnectionSettings, Secrets, Settings}, connection::{ConnectionSettings, Secrets, Settings},
@ -46,7 +50,7 @@ pub enum State {
Finished, Finished,
} }
async fn start_listening<I: Copy>( async fn start_listening<I: Copy + Debug>(
id: I, id: I,
state: State, state: State,
) -> (Option<(I, NetworkManagerEvent)>, State) { ) -> (Option<(I, NetworkManagerEvent)>, State) {
@ -135,7 +139,6 @@ async fn start_listening<I: Copy>(
.cloned() .cloned()
.and_then(|ssid| ssid.try_into().ok()) .and_then(|ssid| ssid.try_into().ok())
.and_then(|ssid| String::from_utf8(ssid).ok()); .and_then(|ssid| String::from_utf8(ssid).ok());
if cur_ssid.as_ref() != Some(&ssid) { if cur_ssid.as_ref() != Some(&ssid) {
continue; continue;
} }
@ -144,7 +147,10 @@ async fn start_listening<I: Copy>(
c.get_secrets("802-11-wireless-security") c.get_secrets("802-11-wireless-security")
.await { .await {
Ok(s) => s, Ok(s) => s,
_ => continue, _ => HashMap::from([("802-11-wireless-security".into(), HashMap::from([
("psk".into(), Value::Str(password.as_str().into()).to_owned()),
("key-mgmt".into(), Value::Str("wpa-psk".into()).to_owned())
]))]),
}; };
if let Some(s) = secrets.get_mut("802-11-wireless-security") { if let Some(s) = secrets.get_mut("802-11-wireless-security") {
s.insert("psk".into(), Value::Str(password.clone().into()).to_owned()); s.insert("psk".into(), Value::Str(password.clone().into()).to_owned());
@ -156,10 +162,22 @@ async fn start_listening<I: Copy>(
.collect::<HashMap<_, _>>()); .collect::<HashMap<_, _>>());
map map
}).collect(); }).collect();
dbg!(settings.clone()); let updated = c.update(settings).await;
let updated = c.update(settings).await.is_ok(); if updated.is_ok() {
if updated { let success = if let Ok(path) = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await {
let success = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await.is_ok(); // let active_conn = ActiveConnection::from(ActiveConnectionProxy::from(conn.1));
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 {
enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default())
} else {
state
};
matches!(s, enums::ActiveConnectionState::Activated)
} else {
false
};
status = (Some((id, NetworkManagerEvent::RequestResponse { status = (Some((id, NetworkManagerEvent::RequestResponse {
req: NetworkManagerRequest::Password(ssid.clone(), password.clone()), req: NetworkManagerRequest::Password(ssid.clone(), password.clone()),
success, success,
@ -172,28 +190,43 @@ async fn start_listening<I: Copy>(
} }
// create a connection // create a connection
for device in network_manager.devices().await.ok().unwrap_or_default() { if status.0.is_none() {
if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) { for device in network_manager.devices().await.ok().unwrap_or_default() {
let conn_settings: HashMap<&str, HashMap<&str, zvariant::Value>> = HashMap::from([ if matches!(device.device_type().await.unwrap_or(DeviceType::Other), DeviceType::Wifi) {
("802-11-wireless".into(), HashMap::from([ let conn_settings: HashMap<&str, HashMap<&str, zvariant::Value>> = HashMap::from([
("ssid".into(), Value::Str(ssid.as_str().into())), ("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())), ("connection".into(), HashMap::from([
("type".into(), Value::Str("802-11-wireless".into())), ("id".into(), Value::Str(ssid.as_str().into())),
])), ("type".into(), Value::Str("802-11-wireless".into())),
("802-11-wireless-security".into(), HashMap::from([ ])),
("psk".into(), Value::Str(password.as_str().into())), ("802-11-wireless-security".into(), HashMap::from([
])) ("psk".into(), Value::Str(password.as_str().into())),
]); ("key-mgmt".into(), Value::Str("wpa-psk".into()))
let success = network_manager.add_and_activate_connection(conn_settings, device.path(), &ObjectPath::try_from("/").unwrap()).await.is_ok(); ]))
status = (Some((id, NetworkManagerEvent::RequestResponse { ]);
req: NetworkManagerRequest::Password(ssid.clone(), password.clone()), let success = if let Ok((_, path)) = network_manager.add_and_activate_connection(conn_settings, device.path(), &ObjectPath::try_from("/").unwrap()).await {
success, let dummy = ActiveConnectionProxy::new(&conn).await.unwrap();
state: NetworkManagerState::new(&conn).await.unwrap_or_default(), let active = ActiveConnectionProxy::builder(&conn).path(path).unwrap().destination(dummy.destination()).unwrap().interface(dummy.interface()).unwrap().build().await.unwrap();
})), false); let state = enums::ActiveConnectionState::from(active.state().await.unwrap_or_default());
let s = if let enums::ActiveConnectionState::Activating = state {
enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default())
} else {
state
};
matches!(s, enums::ActiveConnectionState::Activated)
} else {
false
};
status = (Some((id, NetworkManagerEvent::RequestResponse {
req: NetworkManagerRequest::Password(ssid.clone(), password.clone()),
success,
state: NetworkManagerState::new(&conn).await.unwrap_or_default(),
})), false);
break; break;
}
} }
} }
@ -215,6 +248,9 @@ async fn start_listening<I: Copy>(
// find known connection with matching ssid and activate // find known connection with matching ssid and activate
let mut status = (None, false); 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() { for c in s.list_connections().await.unwrap_or_default() {
let settings = match c.get_settings().await.ok() { let settings = match c.get_settings().await.ok() {
Some(s) => s, Some(s) => s,
@ -232,7 +268,20 @@ async fn start_listening<I: Copy>(
continue; continue;
} }
let success = network_manager.deref().activate_connection(c.deref().path(), &ObjectPath::try_from("/").unwrap(), &ObjectPath::try_from("/").unwrap()).await.is_ok(); 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 {
enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default())
} else {
state
};
matches!(s, enums::ActiveConnectionState::Activated)
} else {
false
};
// dbg!(&success);
status = (Some((id, NetworkManagerEvent::RequestResponse { status = (Some((id, NetworkManagerEvent::RequestResponse {
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()), req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()),
success, success,
@ -241,6 +290,58 @@ async fn start_listening<I: Copy>(
break; break;
} }
// dbg!(&status);
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 {
enums::ActiveConnectionState::from(active.receive_state_changed().await.next().await.unwrap().get().await.unwrap_or_default())
} 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;
}
}
}
// dbg!(&status);
if status.0.is_none() { if status.0.is_none() {
status = (Some((id, NetworkManagerEvent::RequestResponse { status = (Some((id, NetworkManagerEvent::RequestResponse {
req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()), req: NetworkManagerRequest::SelectAccessPoint(ssid.clone()),