Buttplug sex toy control library
1// Buttplug Rust Source Code File - See https://buttplug.io for more info.
2//
3// Copyright 2016-2024 Nonpolynomial Labs LLC. All rights reserved.
4//
5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
6// for full license information.
7
8use super::btleplug_adapter_task::{BtleplugAdapterCommand, BtleplugAdapterTask};
9use buttplug_core::{ButtplugResultFuture, errors::ButtplugDeviceError, util::async_manager};
10use buttplug_server::device::hardware::communication::{
11 HardwareCommunicationManager,
12 HardwareCommunicationManagerBuilder,
13 HardwareCommunicationManagerEvent,
14};
15use futures::future::FutureExt;
16use std::sync::{
17 Arc,
18 atomic::{AtomicBool, Ordering},
19};
20use tokio::sync::mpsc::{Sender, channel};
21
22#[derive(Default, Clone)]
23pub struct BtlePlugCommunicationManagerBuilder {
24 require_keepalive: bool,
25}
26
27impl BtlePlugCommunicationManagerBuilder {
28 pub fn requires_keepalive(&mut self, require: bool) -> &mut Self {
29 self.require_keepalive = require;
30 self
31 }
32}
33
34impl HardwareCommunicationManagerBuilder for BtlePlugCommunicationManagerBuilder {
35 fn finish(
36 &mut self,
37 sender: Sender<HardwareCommunicationManagerEvent>,
38 ) -> Box<dyn HardwareCommunicationManager> {
39 Box::new(BtlePlugCommunicationManager::new(
40 sender,
41 self.require_keepalive,
42 ))
43 }
44}
45
46pub struct BtlePlugCommunicationManager {
47 adapter_event_sender: Sender<BtleplugAdapterCommand>,
48 scanning_status: Arc<AtomicBool>,
49 adapter_connected: Arc<AtomicBool>,
50}
51
52impl BtlePlugCommunicationManager {
53 pub fn new(
54 event_sender: Sender<HardwareCommunicationManagerEvent>,
55 require_keepalive: bool,
56 ) -> Self {
57 let (sender, receiver) = channel(256);
58 let adapter_connected = Arc::new(AtomicBool::new(false));
59 let adapter_connected_clone = adapter_connected.clone();
60 async_manager::spawn(async move {
61 let mut task = BtleplugAdapterTask::new(
62 event_sender,
63 receiver,
64 adapter_connected_clone,
65 require_keepalive,
66 );
67 task.run().await;
68 });
69 Self {
70 adapter_event_sender: sender,
71 scanning_status: Arc::new(AtomicBool::new(false)),
72 adapter_connected,
73 }
74 }
75}
76
77impl HardwareCommunicationManager for BtlePlugCommunicationManager {
78 fn name(&self) -> &'static str {
79 "BtlePlugCommunicationManager"
80 }
81
82 fn start_scanning(&mut self) -> ButtplugResultFuture {
83 let adapter_event_sender = self.adapter_event_sender.clone();
84 let scanning_status = self.scanning_status.clone();
85 // Set to true just to make sure we don't call ScanningFinished too early.
86 scanning_status.store(true, Ordering::Relaxed);
87 async move {
88 if adapter_event_sender
89 .send(BtleplugAdapterCommand::StartScanning)
90 .await
91 .is_err()
92 {
93 error!("Error starting scan, cannot send to btleplug event loop.");
94 scanning_status.store(false, Ordering::Relaxed);
95 Err(
96 ButtplugDeviceError::DeviceConnectionError(
97 "Cannot send start scanning request to event loop.".to_owned(),
98 )
99 .into(),
100 )
101 } else {
102 Ok(())
103 }
104 }
105 .boxed()
106 }
107
108 fn stop_scanning(&mut self) -> ButtplugResultFuture {
109 let adapter_event_sender = self.adapter_event_sender.clone();
110 // Just assume any outcome of this means we're done scanning.
111 self.scanning_status.store(false, Ordering::Relaxed);
112 async move {
113 if adapter_event_sender
114 .send(BtleplugAdapterCommand::StopScanning)
115 .await
116 .is_err()
117 {
118 error!("Error stopping scan, cannot send to btleplug event loop.");
119 Err(
120 ButtplugDeviceError::DeviceConnectionError(
121 "Cannot send stop scanning request to event loop.".to_owned(),
122 )
123 .into(),
124 )
125 } else {
126 Ok(())
127 }
128 }
129 .boxed()
130 }
131
132 fn scanning_status(&self) -> bool {
133 self.scanning_status.load(Ordering::Relaxed)
134 }
135
136 fn can_scan(&self) -> bool {
137 self.adapter_connected.load(Ordering::Relaxed)
138 }
139}
140/*
141impl Drop for BtlePlugCommunicationManager {
142 fn drop(&mut self) {
143 info!("Dropping btleplug comm manager.");
144 if self.adapter.is_some() {
145 if let Err(e) = self.adapter.as_ref().expect("Already checked validity").stop_scan() {
146 info!("Error on scanning shutdown for bluetooth: {:?}", e);
147 }
148 }
149 }
150}
151 */