mod btleplug_device_impl;
mod btleplug_internal;
use crate::{
core::errors::{ButtplugDeviceError, ButtplugError},
server::device_manager::{
DeviceCommunicationEvent, DeviceCommunicationManager, DeviceCommunicationManagerCreator,
},
};
use async_std::{
prelude::StreamExt,
sync::{channel, Sender},
task,
};
use async_trait::async_trait;
use btleplug::api::{Central, CentralEvent, Peripheral};
#[cfg(target_os = "linux")]
use btleplug::bluez::{adapter::ConnectedAdapter, manager::Manager};
#[cfg(any(target_os = "macos", target_os = "ios"))]
use btleplug::corebluetooth::{adapter::Adapter, manager::Manager};
#[cfg(target_os = "windows")]
use btleplug::winrtble::{adapter::Adapter, manager::Manager};
use btleplug_device_impl::BtlePlugDeviceImplCreator;
pub struct BtlePlugCommunicationManager {
manager: Manager,
device_sender: Sender<DeviceCommunicationEvent>,
scanning_sender: Option<Sender<bool>>,
}
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "ios"))]
impl BtlePlugCommunicationManager {
fn get_central(&self) -> Adapter {
self.manager.adapters().unwrap()
}
}
#[cfg(target_os = "linux")]
impl BtlePlugCommunicationManager {
fn get_central(&self) -> ConnectedAdapter {
let adapters = self.manager.adapters().unwrap();
let adapter = adapters.into_iter().nth(0).unwrap();
adapter.connect().unwrap()
}
}
impl DeviceCommunicationManagerCreator for BtlePlugCommunicationManager {
fn new(device_sender: Sender<DeviceCommunicationEvent>) -> Self {
Self {
manager: Manager::new().unwrap(),
device_sender,
scanning_sender: None,
}
}
}
#[async_trait]
impl DeviceCommunicationManager for BtlePlugCommunicationManager {
async fn start_scanning(&mut self) -> Result<(), ButtplugError> {
debug!("Bringing up adapter.");
let central = self.get_central();
let device_sender = self.device_sender.clone();
let (sender, mut receiver) = channel(256);
self.scanning_sender = Some(sender.clone());
task::spawn(async move {
let on_event = move |event: CentralEvent| match event {
CentralEvent::DeviceDiscovered(_) => {
let s = sender.clone();
task::spawn(async move {
s.send(true).await;
});
}
_ => {}
};
central.on_event(Box::new(on_event));
info!("Starting scan.");
central.start_scan().unwrap();
let mut tried_names: Vec<String> = vec![];
while receiver.next().await.unwrap() {
for p in central.peripherals() {
if let Some(name) = p.properties().local_name {
debug!("Found device {}", name);
if name.len() > 0 && !tried_names.contains(&name) {
tried_names.push(name.clone());
let device_creator =
Box::new(BtlePlugDeviceImplCreator::new(p, central.clone()));
device_sender
.send(DeviceCommunicationEvent::DeviceFound(device_creator))
.await;
}
}
}
}
central.stop_scan().unwrap();
info!("Exiting rumble scanning");
});
Ok(())
}
async fn stop_scanning(&mut self) -> Result<(), ButtplugError> {
if self.scanning_sender.is_some() {
let sender = self.scanning_sender.take().unwrap();
sender.send(false).await;
Ok(())
} else {
Err(ButtplugDeviceError::new("Scanning not currently happening.").into())
}
}
fn is_scanning(&mut self) -> bool {
false
}
}
impl Drop for BtlePlugCommunicationManager {
fn drop(&mut self) {
info!("Dropping Comm Manager!");
task::block_on(async {
if let Err(e) = self.stop_scanning().await {
error!("Error stopping scanning during comm manager drop: {:?}", e);
}
});
}
}
#[cfg(test)]
mod test {
use super::BtlePlugCommunicationManager;
use crate::server::device_manager::{
DeviceCommunicationEvent, DeviceCommunicationManager, DeviceCommunicationManagerCreator,
};
use async_std::{prelude::StreamExt, sync::channel, task};
use env_logger;
#[test]
#[ignore]
pub fn test_rumble() {
let _ = env_logger::builder().is_test(true).try_init();
task::block_on(async move {
let (sender, mut receiver) = channel(256);
let mut mgr = BtlePlugCommunicationManager::new(sender);
mgr.start_scanning().await.unwrap();
loop {
match receiver.next().await.unwrap() {
DeviceCommunicationEvent::DeviceFound(_device) => {
info!("Got device!");
info!("Sending message!");
}
_ => assert!(false, "Shouldn't get other message types!"),
}
}
});
}
}