use crate::accessory::BleAccessory;
use crate::error::Result;
use hap_crypto::{AccessoryPairing, ControllerKeypair};
use std::sync::Arc;
use std::time::Duration;
fn format_device_id(id: [u8; 6]) -> String {
use std::fmt::Write as _;
id.iter().fold(String::new(), |mut s, b| {
if !s.is_empty() {
s.push(':');
}
let _ = write!(s, "{b:02x}");
s
})
}
#[async_trait::async_trait]
pub trait SleepyConnector: Send + Sync {
async fn connect(
&self,
device_id: [u8; 6],
pairing: &AccessoryPairing,
broadcast: Option<crate::broadcast_state::BleBroadcastState>,
) -> Result<BleAccessory>;
}
pub struct BluestSleepyConnector {
keypair: ControllerKeypair,
scan_window: Duration,
}
impl BluestSleepyConnector {
#[must_use]
pub fn new(keypair: ControllerKeypair) -> Self {
Self {
keypair,
scan_window: Duration::from_secs(15),
}
}
}
#[async_trait::async_trait]
impl SleepyConnector for BluestSleepyConnector {
async fn connect(
&self,
device_id: [u8; 6],
pairing: &AccessoryPairing,
broadcast: Option<crate::broadcast_state::BleBroadcastState>,
) -> Result<BleAccessory> {
let wanted = format_device_id(device_id);
loop {
let Ok(scanned) = crate::scan(self.scan_window).await else {
tokio::time::sleep(Duration::from_secs(2)).await;
continue;
};
if let Some(found) = scanned
.into_iter()
.find(|d| d.device_id.eq_ignore_ascii_case(&wanted))
{
let conn = crate::connect_gatt(&found).await?;
let advert: Arc<dyn crate::gatt::AdvertSource> = conn.clone();
let ble = crate::BleController::new(self.keypair.clone());
let mut accessory = ble
.connect(
conn as Arc<dyn crate::gatt::GattConnection>,
pairing,
broadcast,
)
.await?;
accessory.set_advert_source(advert);
return Ok(accessory);
}
}
}
}