use std::sync::Arc;
use derive_more::Debug;
use tokio_util::sync::CancellationToken;
use wayle_core::{Property, unwrap_dbus, unwrap_dbus_or};
use wayle_traits::{ModelMonitoring, Reactive};
use zbus::{Connection, zvariant::OwnedObjectPath};
use self::types::{AccessPointParams, Bssid, LiveAccessPointParams};
use crate::{
error::Error,
proxy::access_point::AccessPointProxy,
types::{
flags::{NM80211ApFlags, NM80211ApSecurityFlags},
wifi::NM80211Mode,
},
};
pub(crate) mod monitoring;
pub(crate) mod types;
pub use self::types::{SecurityType, Ssid};
#[derive(Debug, Clone)]
pub struct AccessPoint {
#[debug(skip)]
pub(crate) connection: Connection,
#[debug(skip)]
pub(crate) object_path: OwnedObjectPath,
#[debug(skip)]
pub(crate) cancellation_token: Option<CancellationToken>,
pub flags: Property<NM80211ApFlags>,
pub wpa_flags: Property<NM80211ApSecurityFlags>,
pub rsn_flags: Property<NM80211ApSecurityFlags>,
pub ssid: Property<Ssid>,
pub frequency: Property<u32>,
pub bssid: Property<Bssid>,
pub mode: Property<NM80211Mode>,
pub max_bitrate: Property<u32>,
pub bandwidth: Property<u32>,
pub strength: Property<u8>,
pub last_seen: Property<i32>,
pub security: Property<SecurityType>,
pub is_hidden: Property<bool>,
}
impl Reactive for AccessPoint {
type Context<'a> = AccessPointParams<'a>;
type LiveContext<'a> = LiveAccessPointParams<'a>;
type Error = Error;
async fn get(params: Self::Context<'_>) -> Result<Self, Self::Error> {
let ap = Self::from_path(params.connection, params.path.clone(), None)
.await
.map_err(|e| match e {
Error::ObjectNotFound(_) => e,
_ => Error::ObjectCreationFailed {
object_type: String::from("AccessPoint"),
object_path: params.path.clone(),
source: e.into(),
},
})?;
Ok(ap)
}
async fn get_live(params: Self::LiveContext<'_>) -> Result<Arc<Self>, Self::Error> {
let access_point = Self::from_path(
params.connection,
params.path.clone(),
Some(params.cancellation_token.child_token()),
)
.await
.map_err(|e| match e {
Error::ObjectNotFound(_) => e,
_ => Error::ObjectCreationFailed {
object_type: String::from("AccessPoint"),
object_path: params.path.clone(),
source: e.into(),
},
})?;
let access_point = Arc::new(access_point);
access_point.clone().start_monitoring().await?;
Ok(access_point)
}
}
impl PartialEq for AccessPoint {
fn eq(&self, other: &Self) -> bool {
self.bssid.get() == other.bssid.get()
}
}
impl AccessPoint {
pub fn object_path(&self) -> &OwnedObjectPath {
&self.object_path
}
async fn from_path(
connection: &Connection,
path: OwnedObjectPath,
cancellation_token: Option<CancellationToken>,
) -> Result<Self, Error> {
let ap_proxy = AccessPointProxy::new(connection, &path)
.await
.map_err(Error::DbusError)?;
if ap_proxy.strength().await.is_err() {
return Err(Error::ObjectNotFound(path.clone()));
}
let (
flags,
wpa_flags,
rsn_flags,
ssid,
frequency,
hw_address,
mode,
max_bitrate,
bandwidth,
strength,
last_seen,
) = tokio::join!(
ap_proxy.flags(),
ap_proxy.wpa_flags(),
ap_proxy.rsn_flags(),
ap_proxy.ssid(),
ap_proxy.frequency(),
ap_proxy.hw_address(),
ap_proxy.mode(),
ap_proxy.max_bitrate(),
ap_proxy.bandwidth(),
ap_proxy.strength(),
ap_proxy.last_seen(),
);
let flags = NM80211ApFlags::from_bits_truncate(unwrap_dbus!(flags, path));
let wpa_flags = NM80211ApSecurityFlags::from_bits_truncate(unwrap_dbus!(wpa_flags, path));
let rsn_flags = NM80211ApSecurityFlags::from_bits_truncate(unwrap_dbus!(rsn_flags, path));
let ssid = Ssid::new(unwrap_dbus!(ssid, path));
let frequency = unwrap_dbus!(frequency, path);
let hw_address = Bssid::new(unwrap_dbus!(hw_address, path).into_bytes());
let mode = NM80211Mode::from_u32(unwrap_dbus!(mode, path));
let max_bitrate = unwrap_dbus!(max_bitrate, path);
let bandwidth = unwrap_dbus!(bandwidth, path);
let strength = unwrap_dbus!(strength, path);
let last_seen = unwrap_dbus_or!(last_seen, path, -1);
let security = SecurityType::from_flags(flags, wpa_flags, rsn_flags);
let is_hidden = ssid.is_empty();
Ok(Self {
connection: connection.clone(),
object_path: path.clone(),
cancellation_token,
flags: Property::new(flags),
wpa_flags: Property::new(wpa_flags),
rsn_flags: Property::new(rsn_flags),
ssid: Property::new(ssid),
frequency: Property::new(frequency),
bssid: Property::new(hw_address),
mode: Property::new(mode),
max_bitrate: Property::new(max_bitrate),
bandwidth: Property::new(bandwidth),
strength: Property::new(strength),
last_seen: Property::new(last_seen),
security: Property::new(security),
is_hidden: Property::new(is_hidden),
})
}
}