pub(crate) mod controls;
pub(crate) mod monitoring;
pub(crate) mod types;
use std::{collections::HashMap, sync::Arc};
use controls::AdapterControls;
use derive_more::Debug;
use tokio_util::sync::CancellationToken;
use types::AdapterProperties;
pub use types::{AdapterParams, LiveAdapterParams};
use wayle_core::{Property, unwrap_dbus};
use wayle_traits::{ModelMonitoring, Reactive};
use zbus::{
Connection,
zvariant::{OwnedObjectPath, Value},
};
use crate::{
error::Error,
proxy::adapter::Adapter1Proxy,
types::{
UUID,
adapter::{AdapterRole, AddressType, DiscoveryFilterOptions, PowerState},
},
};
#[derive(Debug, Clone)]
pub struct Adapter {
#[debug(skip)]
pub(crate) zbus_connection: Connection,
#[debug(skip)]
pub(crate) cancellation_token: Option<CancellationToken>,
pub object_path: OwnedObjectPath,
pub address: Property<String>,
pub address_type: Property<AddressType>,
pub name: Property<String>,
pub alias: Property<String>,
pub class: Property<u32>,
pub connectable: Property<bool>,
pub powered: Property<bool>,
pub power_state: Property<PowerState>,
pub discoverable: Property<bool>,
pub discoverable_timeout: Property<u32>,
pub discovering: Property<bool>,
pub pairable: Property<bool>,
pub pairable_timeout: Property<u32>,
pub uuids: Property<Vec<UUID>>,
pub modalias: Property<Option<String>>,
pub roles: Property<Vec<AdapterRole>>,
pub experimental_features: Property<Vec<UUID>>,
pub manufacturer: Property<u16>,
pub version: Property<u8>,
}
impl PartialEq for Adapter {
fn eq(&self, other: &Self) -> bool {
self.object_path == other.object_path
}
}
impl Reactive for Adapter {
type Error = Error;
type Context<'a> = AdapterParams<'a>;
type LiveContext<'a> = LiveAdapterParams<'a>;
async fn get(context: Self::Context<'_>) -> Result<Self, Self::Error> {
let adapter_proxy = Adapter1Proxy::new(context.connection, &context.path).await?;
let props = Self::fetch_properties(&adapter_proxy).await?;
Ok(Self::from_properties(
props,
context.connection,
context.path,
None,
))
}
async fn get_live(context: Self::LiveContext<'_>) -> Result<Arc<Self>, Self::Error> {
let adapter_proxy = Adapter1Proxy::new(context.connection, &context.path).await?;
let props = Self::fetch_properties(&adapter_proxy).await?;
let adapter = Self::from_properties(
props,
context.connection,
context.path.clone(),
Some(context.cancellation_token.child_token()),
);
let adapter_arc = Arc::new(adapter);
adapter_arc.clone().start_monitoring().await?;
Ok(adapter_arc)
}
}
impl Adapter {
pub async fn set_alias(&self, alias: &str) -> Result<(), Error> {
AdapterControls::set_alias(&self.zbus_connection, &self.object_path, alias).await
}
pub async fn set_connectable(&self, connectable: bool) -> Result<(), Error> {
AdapterControls::set_connectable(&self.zbus_connection, &self.object_path, connectable)
.await
}
pub async fn set_powered(&self, powered: bool) -> Result<(), Error> {
AdapterControls::set_powered(&self.zbus_connection, &self.object_path, powered).await
}
pub async fn set_discoverable(&self, discoverable: bool) -> Result<(), Error> {
AdapterControls::set_discoverable(&self.zbus_connection, &self.object_path, discoverable)
.await
}
pub async fn set_discoverable_timeout(&self, timeout: u32) -> Result<(), Error> {
AdapterControls::set_discoverable_timeout(&self.zbus_connection, &self.object_path, timeout)
.await
}
pub async fn set_pairable(&self, pairable: bool) -> Result<(), Error> {
AdapterControls::set_pairable(&self.zbus_connection, &self.object_path, pairable).await
}
pub async fn set_pairable_timeout(&self, timeout: u32) -> Result<(), Error> {
AdapterControls::set_pairable_timeout(&self.zbus_connection, &self.object_path, timeout)
.await
}
pub async fn set_discovery_filter(
&self,
options: DiscoveryFilterOptions<'_>,
) -> Result<(), Error> {
let filter = options.to_filter();
AdapterControls::set_discovery_filter(&self.zbus_connection, &self.object_path, filter)
.await
}
pub async fn start_discovery(&self) -> Result<(), Error> {
AdapterControls::start_discovery(&self.zbus_connection, &self.object_path).await
}
pub async fn stop_discovery(&self) -> Result<(), Error> {
AdapterControls::stop_discovery(&self.zbus_connection, &self.object_path).await
}
pub async fn remove_device(&self, device_path: &OwnedObjectPath) -> Result<(), Error> {
AdapterControls::remove_device(&self.zbus_connection, &self.object_path, device_path).await
}
pub async fn get_discovery_filters(&self) -> Result<Vec<String>, Error> {
AdapterControls::get_discovery_filters(&self.zbus_connection, &self.object_path).await
}
pub async fn connect_device(
&self,
properties: HashMap<String, Value<'_>>,
) -> Result<OwnedObjectPath, Error> {
AdapterControls::connect_device(&self.zbus_connection, &self.object_path, properties).await
}
#[allow(clippy::too_many_lines)]
async fn fetch_properties(proxy: &Adapter1Proxy<'_>) -> Result<AdapterProperties, Error> {
let (
address,
address_type,
name,
alias,
class,
connectable,
powered,
power_state,
discoverable,
discoverable_timeout,
discovering,
pairable,
pairable_timeout,
uuids,
modalias,
roles,
experimental_features,
manufacturer,
version,
) = tokio::join!(
proxy.address(),
proxy.address_type(),
proxy.name(),
proxy.alias(),
proxy.class(),
proxy.connectable(),
proxy.powered(),
proxy.power_state(),
proxy.discoverable(),
proxy.discoverable_timeout(),
proxy.discovering(),
proxy.pairable(),
proxy.pairable_timeout(),
proxy.uuids(),
proxy.modalias(),
proxy.roles(),
proxy.experimental_features(),
proxy.manufacturer(),
proxy.version()
);
Ok(AdapterProperties {
address: unwrap_dbus!(address),
address_type: unwrap_dbus!(address_type),
name: unwrap_dbus!(name),
alias: unwrap_dbus!(alias),
class: unwrap_dbus!(class),
connectable: unwrap_dbus!(connectable),
powered: unwrap_dbus!(powered),
power_state: unwrap_dbus!(power_state),
discoverable: unwrap_dbus!(discoverable),
discoverable_timeout: unwrap_dbus!(discoverable_timeout),
discovering: unwrap_dbus!(discovering),
pairable: unwrap_dbus!(pairable),
pairable_timeout: unwrap_dbus!(pairable_timeout),
uuids: unwrap_dbus!(uuids),
modalias: modalias.ok(),
roles: unwrap_dbus!(roles),
experimental_features: unwrap_dbus!(experimental_features),
manufacturer: unwrap_dbus!(manufacturer),
version: unwrap_dbus!(version),
})
}
fn from_properties(
props: AdapterProperties,
connection: &Connection,
object_path: OwnedObjectPath,
cancellation_token: Option<CancellationToken>,
) -> Self {
Self {
object_path,
zbus_connection: connection.clone(),
cancellation_token,
address: Property::new(props.address),
address_type: Property::new(AddressType::from(props.address_type.as_str())),
name: Property::new(props.name),
alias: Property::new(props.alias),
class: Property::new(props.class),
connectable: Property::new(props.connectable),
powered: Property::new(props.powered),
power_state: Property::new(PowerState::from(props.power_state.as_str())),
discoverable: Property::new(props.discoverable),
discoverable_timeout: Property::new(props.discoverable_timeout),
discovering: Property::new(props.discovering),
pairable: Property::new(props.pairable),
pairable_timeout: Property::new(props.pairable_timeout),
uuids: Property::new(
props
.uuids
.into_iter()
.map(|s| UUID::from(s.as_str()))
.collect(),
),
modalias: Property::new(props.modalias),
roles: Property::new(
props
.roles
.into_iter()
.map(|s| AdapterRole::from(s.as_str()))
.collect(),
),
experimental_features: Property::new(
props
.experimental_features
.into_iter()
.map(|s| UUID::from(s.as_str()))
.collect(),
),
manufacturer: Property::new(props.manufacturer),
version: Property::new(props.version),
}
}
}