use std::ops::{Bound, RangeBounds};
use uuid::Uuid;
use zbus::{Connection, interface};
use zvariant::OwnedObjectPath;
use crate::{iwd_interface::IwdInterface, station::Station};
pub trait SignalLevelAgent: Send + Sync + 'static {
fn release(&self) {}
fn changed(&self, station: &Station, signal_level: impl RangeBounds<i16>);
}
pub struct SignalLevelInterface<A> {
pub(super) agent: A,
pub(super) connection: Connection,
pub(super) levels: Vec<i16>,
}
#[interface(name = "net.connman.iwd.SignalLevelAgent")]
impl<A: SignalLevelAgent> SignalLevelInterface<A> {
#[zbus(name = "Release")]
fn release(&self) {
self.agent.release();
}
#[zbus(name = "Changed")]
async fn changed(&self, station_path: OwnedObjectPath, level_idx: u8) -> zbus::fdo::Result<()> {
let station = Station::new(self.connection.clone(), station_path).await?;
let level_idx = usize::from(level_idx);
let max_strength = level_idx
.checked_sub(1)
.and_then(|level| self.levels.get(level))
.map(|level| Bound::Excluded(*level))
.unwrap_or(Bound::Unbounded);
let min_strength = self
.levels
.get(level_idx)
.map(|level| Bound::Included(*level))
.unwrap_or(Bound::Unbounded);
self.agent.changed(&station, (min_strength, max_strength));
Ok(())
}
}
pub struct SignalLevelAgentManager {
pub(crate) dbus_path: OwnedObjectPath,
pub(crate) station: super::Station,
}
impl SignalLevelAgentManager {
pub(crate) async fn register_agent(
station: super::Station,
interface: SignalLevelInterface<impl SignalLevelAgent>,
) -> zbus::Result<Self> {
let dbus_path = OwnedObjectPath::try_from(format!(
"/iwdrs/signal_level_agent/{}",
Uuid::new_v4().as_simple()
))?;
station
.proxy
.connection()
.object_server()
.at(dbus_path.clone(), interface)
.await?;
Ok(Self { dbus_path, station })
}
pub async fn unregister(self) -> zbus::Result<()> {
self.station
.proxy
.call_method("UnregisterSignalLevelAgent", &(&self.dbus_path,))
.await?;
Ok(())
}
}