use super::internal::{
CoreBluetoothEvent, CoreBluetoothMessage, CoreBluetoothReply, CoreBluetoothReplyFuture,
run_corebluetooth_thread,
};
use super::peripheral::{Peripheral, PeripheralId};
use crate::api::{Central, CentralEvent, CentralState, ScanFilter};
use crate::common::adapter_manager::AdapterManager;
use crate::{Error, Result};
use async_trait::async_trait;
use futures::channel::mpsc::{self, Sender};
use futures::sink::SinkExt;
use futures::stream::{Stream, StreamExt};
use log::*;
use objc2_core_bluetooth::CBManagerState;
use std::pin::Pin;
use std::sync::Arc;
use tokio::task;
#[derive(Clone, Debug)]
pub struct Adapter {
manager: Arc<AdapterManager<Peripheral>>,
sender: Sender<CoreBluetoothMessage>,
}
fn get_central_state(state: CBManagerState) -> CentralState {
match state {
CBManagerState::PoweredOn => CentralState::PoweredOn,
CBManagerState::PoweredOff => CentralState::PoweredOff,
_ => CentralState::Unknown,
}
}
impl Adapter {
pub(crate) async fn new() -> Result<Self> {
let (sender, mut receiver) = mpsc::channel(256);
let adapter_sender = run_corebluetooth_thread(sender)?;
debug!("Waiting on adapter connect");
if !matches!(
receiver.next().await,
Some(CoreBluetoothEvent::DidUpdateState { state: _ })
) {
return Err(Error::Other(
"Adapter failed to connect.".to_string().into(),
));
}
debug!("Adapter connected");
let manager = Arc::new(AdapterManager::default());
let manager_clone = manager.clone();
let adapter_sender_clone = adapter_sender.clone();
task::spawn(async move {
while let Some(msg) = receiver.next().await {
match msg {
CoreBluetoothEvent::DeviceDiscovered {
uuid,
local_name,
advertisement_name,
event_receiver,
} => {
manager_clone.add_peripheral(Peripheral::new(
uuid,
local_name,
advertisement_name,
Arc::downgrade(&manager_clone),
event_receiver,
adapter_sender_clone.clone(),
));
manager_clone.emit(CentralEvent::DeviceDiscovered(uuid.into()));
}
CoreBluetoothEvent::DeviceUpdated {
uuid,
local_name,
advertisement_name,
} => {
let id = uuid.into();
if let Some(entry) = manager_clone.peripheral_mut(&id) {
entry.value().update_name(local_name, advertisement_name);
manager_clone.emit(CentralEvent::DeviceUpdated(id));
}
}
CoreBluetoothEvent::DeviceDisconnected { uuid } => {
manager_clone.emit(CentralEvent::DeviceDisconnected(uuid.into()));
}
CoreBluetoothEvent::DidUpdateState { state } => {
let central_state = get_central_state(state);
manager_clone.emit(CentralEvent::StateUpdate(central_state));
}
}
}
});
Ok(Adapter {
manager,
sender: adapter_sender,
})
}
}
#[async_trait]
impl Central for Adapter {
type Peripheral = Peripheral;
async fn events(&self) -> Result<Pin<Box<dyn Stream<Item = CentralEvent> + Send>>> {
Ok(self.manager.event_stream())
}
async fn start_scan(&self, filter: ScanFilter) -> Result<()> {
self.sender
.to_owned()
.send(CoreBluetoothMessage::StartScanning { filter })
.await?;
Ok(())
}
async fn stop_scan(&self) -> Result<()> {
self.sender
.to_owned()
.send(CoreBluetoothMessage::StopScanning)
.await?;
Ok(())
}
async fn peripherals(&self) -> Result<Vec<Peripheral>> {
Ok(self.manager.peripherals())
}
async fn peripheral(&self, id: &PeripheralId) -> Result<Peripheral> {
self.manager.peripheral(id).ok_or(Error::DeviceNotFound)
}
async fn add_peripheral(&self, _address: &PeripheralId) -> Result<Peripheral> {
Err(Error::NotSupported(
"Can't add a Peripheral from a PeripheralId".to_string(),
))
}
async fn clear_peripherals(&self) -> Result<()> {
self.manager.clear_peripherals();
Ok(())
}
async fn adapter_info(&self) -> Result<String> {
Ok("CoreBluetooth".to_string())
}
async fn adapter_state(&self) -> Result<CentralState> {
let fut = CoreBluetoothReplyFuture::default();
self.sender
.to_owned()
.send(CoreBluetoothMessage::GetAdapterState {
future: fut.get_state_clone(),
})
.await?;
match fut.await {
CoreBluetoothReply::AdapterState(state) => {
let central_state = get_central_state(state);
return Ok(central_state.clone());
}
_ => panic!("Shouldn't get anything but a AdapterState!"),
}
}
}