Rewrite available wifi code into something much cleaner

This commit is contained in:
Lucy 2022-02-02 16:22:43 -05:00
parent f3a20ec7b2
commit 585946bbfa
No known key found for this signature in database
GPG key ID: EBC517FAD666BBF1

View file

@ -1,135 +1,65 @@
// SPDX-License-Identifier: LGPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later
use crate::task;
use cosmic_dbus_networkmanager::{ use cosmic_dbus_networkmanager::{
device::SpecificDevice, interface::enums::ApSecurityFlags, nm::NetworkManager, device::{wireless::WirelessDevice, SpecificDevice},
nm::NetworkManager,
}; };
use futures_util::{StreamExt, TryFutureExt}; use futures_util::StreamExt;
use gtk4::{ use gtk4::{
glib, prelude::*, Align, Button, Dialog, HeaderBar, Image, Label, Orientation, ScrolledWindow, glib::{source::PRIORITY_DEFAULT, MainContext, Sender},
Spinner, prelude::*,
};
use itertools::Itertools;
use slotmap::{DefaultKey, SlotMap};
use std::{
rc::Rc,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
}; };
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
use zbus::Connection; use zbus::Connection;
pub fn add_available_wifi(target: &gtk4::Box) {} pub fn add_available_wifi(target: &gtk4::Box) {
let (tx, rx) = MainContext::channel::<Vec<AccessPoint>>(PRIORITY_DEFAULT);
task::spawn(scan_for_wifi(tx));
rx.attach(None, |aps| Continue(true));
}
async fn scan_for_devices(tx: UnboundedSender<SlotMap<DefaultKey, AccessPoint>>) { async fn scan_for_wifi(tx: Sender<Vec<AccessPoint>>) -> zbus::Result<()> {
let sys_conn = match Connection::system().await { let conn = Connection::system().await?;
Ok(conn) => conn, let network_manager = NetworkManager::new(&conn).await?;
Err(err) => { loop {
//error!(%err, "Failed to connect to system dbus session"); let devices = network_manager.devices().await?;
return; for device in devices {
if let Ok(Some(SpecificDevice::Wireless(wireless_device))) =
device.downcast_to_device().await
{
handle_wireless_device(wireless_device, tx.clone()).await?;
} }
};
let nm = match NetworkManager::new(&sys_conn).await {
Ok(p) => p,
Err(err) => {
//error!(%err, "Failed to set up connection to NetworkManager dbus");
return;
} }
}; tokio::time::sleep(std::time::Duration::from_secs(5)).await;
let devices = match nm.devices().await { }
Ok(d) => d,
Err(err) => {
//error!(%err, "Failed to get devices from NetworkManager");
return;
} }
};
let mut all_aps = SlotMap::new();
for d in devices { async fn handle_wireless_device(
if let Ok(Some(SpecificDevice::Wireless(w))) = d.downcast_to_device().await { device: WirelessDevice<'_>,
let id = d tx: Sender<Vec<AccessPoint>>,
.active_connection() ) -> zbus::Result<()> {
.and_then(|ac| async move { ac.id().await }) device
.await .request_scan(std::collections::HashMap::new())
.unwrap_or_else(|_| "unknown".to_string()); .await?;
if let Err(err) = w.request_scan(std::collections::HashMap::new()).await { let mut scan_changed = device.receive_last_scan_changed().await;
//error!(%err, %id, "Wi-Fi scan failed");
continue;
};
let mut scan_changed = w.receive_last_scan_changed().await;
if let Some(t) = scan_changed.next().await { if let Some(t) = scan_changed.next().await {
if let Ok(t) = t.get().await { if let Ok(-1) = t.get().await {
if t == -1 { return Ok(());
//error!(%id, "Getting access point failed");
continue;
} }
} }
match w.get_access_points().await { let access_points = device.get_access_points().await?;
Ok(aps) => { let mut aps = Vec::with_capacity(access_points.len());
if !aps.is_empty() { for ap in access_points {
for ap in AccessPoint::from_list(aps).await { aps.push(AccessPoint {
all_aps.insert(ap); ssid: String::from_utf8_lossy(&ap.ssid().await?.clone()).into_owned(),
strength: ap.strength().await?,
});
}
Ok(())
} }
break; struct AccessPoint {
} ssid: String,
} strength: u8,
Err(err) => {
//error!(%err, %id, "Getting access points failed");
continue;
}
};
}
}
}
if let Err(err) = tx.send(all_aps) {
//error!(%err, "failed to send AP list");
}
}
#[derive(Debug)]
pub struct AccessPoint {
pub ssid: String,
pub hw_address: String,
pub strength: u8,
pub wpa_flags: ApSecurityFlags,
}
impl AccessPoint {
pub async fn new(
ap: cosmic_dbus_networkmanager::access_point::AccessPoint<'_>,
) -> Option<Self> {
Some(Self {
ssid: ap
.ssid()
.await
.map(|x| String::from_utf8_lossy(&x).into_owned())
.ok()?,
hw_address: ap.hw_address().await.ok()?,
strength: ap.strength().await.ok()?,
wpa_flags: ap.wpa_flags().await.ok()?,
})
}
pub async fn from_list(
aps: Vec<cosmic_dbus_networkmanager::access_point::AccessPoint<'_>>,
) -> Vec<Self> {
let mut out = Vec::<Self>::with_capacity(aps.len());
for ap in aps {
if let Some(ap) = Self::new(ap).await {
out.push(ap);
}
}
let mut ret = out
.into_iter()
.sorted_by(|a, b| a.strength.cmp(&b.strength))
.rev()
.unique_by(|ap| ap.ssid.clone())
.collect::<Vec<Self>>();
// for some reason adding .rev() messes up unique_by, so we do this instead
ret.reverse();
ret
}
} }