1use std::collections::HashMap;
4
5use bluer::AdapterEvent;
6use futures::FutureExt;
7use futures::StreamExt;
8
9#[async_trait::async_trait]
14impl super::BluetoothRfcommConnectableAsyncTrait for bluer::rfcomm::ConnectRequest {
15 async fn accept(self) -> Result<(crate::BluetoothStream, [u8; 6], u8), String> {
16 let s = bluer::rfcomm::ConnectRequest::accept(self);
17 match s {
18 Ok(s) => {
19 let addr = s.peer_addr().map_err(|e| e.to_string())?;
20 Ok((
21 crate::BluetoothStream::Bluez(Box::pin(s)),
22 *addr.addr,
23 addr.channel,
24 ))
25 }
26 Err(e) => Err(e.to_string()),
27 }
28 }
29}
30
31impl super::BluetoothRfcommProfileAsyncTrait for bluer::rfcomm::ProfileHandle {
36 async fn connectable(&mut self) -> Result<crate::BluetoothRfcommConnectableAsync, String> {
37 self.next()
38 .await
39 .map(|a| crate::BluetoothRfcommConnectableAsync::Bluez(a))
40 .ok_or_else(|| "Failed to get bluetooth connection".to_string())
41 }
42}
43
44enum BluetoothConnection {
50 Rfcomm(bluer::rfcomm::Stream),
52 L2cap(bluer::l2cap::Stream),
54}
55
56impl std::io::Read for BluetoothConnection {
57 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
58 tokio::task::block_in_place(|| {
59 tokio::runtime::Handle::current().block_on(async {
60 use tokio::io::AsyncReadExt;
61 match self {
62 BluetoothConnection::Rfcomm(s) => s.read(buf).await,
63 BluetoothConnection::L2cap(s) => s.read(buf).await,
64 }
65 })
66 })
67 }
68}
69
70impl std::io::Write for BluetoothConnection {
71 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
72 tokio::task::block_in_place(|| {
73 tokio::runtime::Handle::current().block_on(async {
74 use tokio::io::AsyncWriteExt;
75 match self {
76 BluetoothConnection::Rfcomm(s) => s.write(buf).await,
77 BluetoothConnection::L2cap(s) => s.write(buf).await,
78 }
79 })
80 })
81 }
82
83 fn flush(&mut self) -> std::io::Result<()> {
84 tokio::task::block_in_place(|| {
85 tokio::runtime::Handle::current().block_on(async {
86 use tokio::io::AsyncWriteExt;
87 match self {
88 BluetoothConnection::Rfcomm(s) => s.flush().await,
89 BluetoothConnection::L2cap(s) => s.flush().await,
90 }
91 })
92 })
93 }
94}
95
96pub struct BluetoothRfcommSocket {
104 device_addr: bluer::Address,
106 rfcomm_channel: Option<u8>,
114 l2cap_psm: Option<u16>,
116 is_secure: bool,
118 connection: Option<BluetoothConnection>,
120}
121
122impl BluetoothRfcommSocket {
123 fn new_rfcomm(device_addr: bluer::Address, channel: u8, is_secure: bool) -> Self {
125 Self {
126 device_addr,
127 rfcomm_channel: Some(channel),
128 l2cap_psm: None,
129 is_secure,
130 connection: None,
131 }
132 }
133
134 fn new_l2cap(device_addr: bluer::Address, psm: u16, is_secure: bool) -> Self {
136 Self {
137 device_addr,
138 rfcomm_channel: None,
139 l2cap_psm: Some(psm),
140 is_secure,
141 connection: None,
142 }
143 }
144}
145
146impl crate::BluetoothSocketTrait for BluetoothRfcommSocket {
147 fn is_connected(&self) -> Result<bool, std::io::Error> {
148 Ok(self.connection.is_some())
149 }
150
151 fn connect(&mut self) -> Result<(), std::io::Error> {
152 if self.connection.is_some() {
153 return Ok(());
154 }
155 tokio::task::block_in_place(|| {
156 tokio::runtime::Handle::current().block_on(async {
157 if let Some(channel) = self.rfcomm_channel {
158 let addr = bluer::rfcomm::SocketAddr::new(self.device_addr, channel);
159 let socket = bluer::rfcomm::Socket::new()
160 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
161 if self.is_secure {
162 socket
163 .set_security(bluer::rfcomm::Security {
164 level: bluer::rfcomm::SecurityLevel::Medium,
165 key_size: 0,
166 })
167 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
168 }
169 let stream = socket
170 .connect(addr)
171 .await
172 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
173 log::info!("STREAM {:?} to {:?}", stream.as_ref().local_addr(), stream.peer_addr());
174 self.connection = Some(BluetoothConnection::Rfcomm(stream));
175 log::info!("Got an rfcomm stream");
176 } else if let Some(psm) = self.l2cap_psm {
177 let addr = bluer::l2cap::SocketAddr::new(
178 self.device_addr,
179 bluer::AddressType::BrEdr,
180 psm,
181 );
182 let socket = bluer::l2cap::Socket::<bluer::l2cap::Stream>::new_stream()
183 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
184 if self.is_secure {
185 socket
186 .set_security(bluer::l2cap::Security {
187 level: bluer::l2cap::SecurityLevel::Medium,
188 key_size: 0,
189 })
190 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
191 }
192 let stream = socket
193 .connect(addr)
194 .await
195 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
196 self.connection = Some(BluetoothConnection::L2cap(stream));
197 } else {
198 return Err(std::io::Error::new(
199 std::io::ErrorKind::InvalidInput,
200 "BluetoothRfcommSocket has neither an RFCOMM channel nor an L2CAP PSM configured",
201 ));
202 }
203 Ok(())
204 })
205 })
206 }
207}
208
209impl std::io::Read for BluetoothRfcommSocket {
210 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
211 match &mut self.connection {
212 Some(conn) => conn.read(buf),
213 None => Err(std::io::Error::from(std::io::ErrorKind::NotConnected)),
214 }
215 }
216}
217
218impl std::io::Write for BluetoothRfcommSocket {
219 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
220 match &mut self.connection {
221 Some(conn) => conn.write(buf),
222 None => Err(std::io::Error::from(std::io::ErrorKind::NotConnected)),
223 }
224 }
225
226 fn flush(&mut self) -> std::io::Result<()> {
227 match &mut self.connection {
228 Some(conn) => conn.flush(),
229 None => Err(std::io::Error::from(std::io::ErrorKind::NotConnected)),
230 }
231 }
232}
233
234pub struct LinuxBluetoothDevice {
242 device: bluer::Device,
244}
245
246impl LinuxBluetoothDevice {
247 pub fn new(device: bluer::Device) -> Self {
249 Self { device }
250 }
251}
252
253impl super::BluetoothDeviceTrait for LinuxBluetoothDevice {
254 fn get_uuids(&mut self) -> Result<Vec<crate::BluetoothUuid>, std::io::Error> {
255 tokio::task::block_in_place(|| {
256 tokio::runtime::Handle::current().block_on(async {
257 let uuids =
258 self.device.uuids().await.map_err(|e| {
259 std::io::Error::new(std::io::ErrorKind::Other, e.to_string())
260 })?;
261 Ok(uuids
262 .unwrap_or_default()
263 .into_iter()
264 .map(|u| {
265 use std::str::FromStr;
266 crate::BluetoothUuid::from_str(&u.to_string())
267 .unwrap_or_else(|_| crate::BluetoothUuid::Unknown(u.to_string()))
268 })
269 .collect())
270 })
271 })
272 }
273
274 fn get_name(&self) -> Result<String, std::io::Error> {
277 let device = self.device.clone();
278 tokio::task::block_in_place(|| {
279 tokio::runtime::Handle::current().block_on(async move {
280 device
281 .alias()
282 .await
283 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
284 })
285 })
286 }
287
288 fn get_address(&mut self) -> Result<String, std::io::Error> {
289 Ok(self.device.address().to_string())
290 }
291
292 fn get_pair_state(&self) -> Result<crate::PairingStatus, std::io::Error> {
293 let device = self.device.clone();
294 tokio::task::block_in_place(|| {
295 tokio::runtime::Handle::current().block_on(async move {
296 let paired = device
297 .is_paired()
298 .await
299 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
300 Ok(if paired {
301 crate::PairingStatus::Paired
302 } else {
303 crate::PairingStatus::NotPaired
304 })
305 })
306 })
307 }
308
309 fn get_l2cap_socket(
318 &mut self,
319 psm: u16,
320 is_secure: bool,
321 ) -> Result<crate::BluetoothSocket, String> {
322 let addr = self.device.address();
323 let socket = BluetoothRfcommSocket::new_l2cap(addr, psm, is_secure);
324 Ok(crate::BluetoothSocket::Bluez(socket))
325 }
326
327 fn get_rfcomm_socket(
336 &mut self,
337 channel: u8,
338 is_secure: bool,
339 ) -> Result<crate::BluetoothSocket, String> {
340 let addr = self.device.address();
341 let socket = BluetoothRfcommSocket::new_rfcomm(addr, channel, is_secure);
342 Ok(crate::BluetoothSocket::Bluez(socket))
343 }
344}
345
346pub struct BluetoothDiscovery {}
352
353impl BluetoothDiscovery {
354 fn new() -> Self {
356 Self {}
357 }
358}
359
360impl super::BluetoothDiscoveryTrait for BluetoothDiscovery {}
361
362impl Drop for BluetoothDiscovery {
363 fn drop(&mut self) {}
364}
365
366impl TryFrom<super::BluetoothRfcommProfileSettings> for bluer::rfcomm::Profile {
371 type Error = String;
372 fn try_from(value: super::BluetoothRfcommProfileSettings) -> Result<Self, Self::Error> {
373 let service = if let Some(v) = value.service_uuid {
374 Some(bluer::Uuid::parse_str(&v).map_err(|e| e.to_string())?)
375 } else {
376 None
377 };
378 Ok(Self {
379 uuid: bluer::Uuid::parse_str(&value.uuid).map_err(|e| e.to_string())?,
380 name: value.name,
381 service,
382 role: if value.channel.is_some() {
383 Some(bluer::rfcomm::Role::Server)
384 } else {
385 None
386 },
387 channel: value.channel,
388 psm: value.psm,
389 require_authentication: value.authenticate,
390 require_authorization: value.authorize,
391 auto_connect: value.auto_connect,
392 service_record: value.sdp_record,
393 version: value.sdp_version,
394 features: value.sdp_features,
395 ..Default::default()
396 })
397 }
398}
399
400impl TryFrom<super::BluetoothL2capProfileSettings> for bluer::rfcomm::Profile {
404 type Error = String;
405 fn try_from(value: super::BluetoothL2capProfileSettings) -> Result<Self, Self::Error> {
406 let service = if let Some(v) = value.service_uuid {
407 Some(bluer::Uuid::parse_str(&v).map_err(|e| e.to_string())?)
408 } else {
409 None
410 };
411 Ok(Self {
412 uuid: bluer::Uuid::parse_str(&value.uuid).map_err(|e| e.to_string())?,
413 name: value.name,
414 service,
415 role: None,
416 channel: None,
417 psm: value.psm,
418 require_authentication: value.authenticate,
419 require_authorization: value.authorize,
420 auto_connect: value.auto_connect,
421 service_record: value.sdp_record,
422 version: value.sdp_version,
423 features: value.sdp_features,
424 ..Default::default()
425 })
426 }
427}
428
429pub struct BluetoothHandler {
435 session: bluer::Session,
437 adapters: Vec<bluer::Adapter>,
439 _blue_agent_handle: bluer::agent::AgentHandle,
441}
442
443impl super::BluetoothAdapterTrait for BluetoothHandler {
444 fn supports_async(&self) -> Option<&dyn super::AsyncBluetoothAdapterTrait> {
445 Some(self)
446 }
447
448 fn supports_sync(&self) -> Option<&dyn super::SyncBluetoothAdapterTrait> {
449 None
450 }
451}
452
453#[async_trait::async_trait]
454impl super::AsyncBluetoothAdapterTrait for BluetoothHandler {
455 async fn register_rfcomm_profile(
456 &self,
457 settings: super::BluetoothRfcommProfileSettings,
458 ) -> Result<crate::BluetoothRfcommProfileAsync, String> {
459 self.session
460 .register_profile(settings.try_into()?)
461 .await
462 .map(|a| super::BluetoothRfcommProfileAsync::Bluez(a.into()))
463 .map_err(|e| e.to_string())
464 }
465
466 async fn register_l2cap_profile(
472 &self,
473 settings: super::BluetoothL2capProfileSettings,
474 ) -> Result<crate::BluetoothL2capProfileAsync, String> {
475 self.session
476 .register_profile(settings.try_into()?)
477 .await
478 .map(|a| super::BluetoothL2capProfileAsync::Bluez(a.into()))
479 .map_err(|e| e.to_string())
480 }
481
482 fn start_discovery(&self) -> crate::BluetoothDiscovery {
483 BluetoothDiscovery::new().into()
484 }
485
486 fn get_paired_devices(&self) -> Option<Vec<crate::BluetoothDevice>> {
488 let mut list = Vec::new();
489 for adapter in &self.adapters {
490 let result = tokio::task::block_in_place(|| {
491 tokio::runtime::Handle::current().block_on(async {
492 let addrs = adapter.device_addresses().await?;
493 let mut paired = Vec::new();
494 for addr in addrs {
495 if let Ok(dev) = adapter.device(addr) {
496 if dev.is_paired().await.unwrap_or(false) {
497 paired.push(dev);
498 }
499 }
500 }
501 Ok::<Vec<bluer::Device>, bluer::Error>(paired)
502 })
503 });
504 if let Ok(devices) = result {
505 for dev in devices {
506 list.push(crate::BluetoothDevice::Bluez(LinuxBluetoothDevice::new(
507 dev,
508 )));
509 }
510 }
511 }
512 Some(list)
513 }
514
515 async fn addresses(&self) -> Vec<super::BluetoothAdapterAddress> {
516 let mut a = Vec::new();
517 for adapter in &self.adapters {
518 if let Ok(adr) = adapter.address().await {
519 a.push(super::BluetoothAdapterAddress::Byte(adr.0));
520 }
521 }
522 a
523 }
524
525 async fn set_discoverable(&self, d: bool) -> Result<(), ()> {
526 for adapter in &self.adapters {
527 adapter.set_discoverable(d).await.map_err(|_| ())?;
528 }
529 Ok(())
530 }
531}
532
533impl BluetoothHandler {
534 pub async fn addresses(&self) -> Vec<bluer::Address> {
536 let mut addrs = Vec::new();
537 for a in &self.adapters {
538 if let Ok(addr) = a.address().await {
539 addrs.push(addr);
540 }
541 }
542 addrs
543 }
544
545 pub async fn new(
547 s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
548 ) -> Result<Self, String> {
549 let session = bluer::Session::new().await.map_err(|e| e.to_string())?;
550
551 let adapter_names = session.adapter_names().await.map_err(|e| e.to_string())?;
552 let adapters: Vec<bluer::Adapter> = adapter_names
553 .iter()
554 .filter_map(|n| session.adapter(n).ok())
555 .collect();
556
557 let blue_agent = Self::build_agent(s);
558 let blue_agent_handle = session.register_agent(blue_agent).await;
559 println!("Registered a bluetooth agent {}", blue_agent_handle.is_ok());
560 Ok(Self {
561 session,
562 adapters,
563 _blue_agent_handle: blue_agent_handle.map_err(|e| e.to_string())?,
564 })
565 }
566
567 async fn enable(&mut self) {
569 for adapter in &self.adapters {
570 adapter.set_powered(true).await.unwrap();
571 adapter.set_pairable(true).await.unwrap();
572 }
573 }
574
575 async fn disable(&mut self) {
577 self.set_discoverable(false).await;
578 for adapter in &self.adapters {
579 adapter.set_powered(false).await.unwrap();
580 adapter.set_pairable(false).await.unwrap();
581 }
582 }
583
584 pub async fn set_discoverable(&mut self, d: bool) {
586 for adapter in &self.adapters {
587 adapter.set_discoverable(d).await.unwrap();
588 }
589 }
590
591 pub async fn register_rfcomm_profile(
593 &mut self,
594 profile: bluer::rfcomm::Profile,
595 ) -> Result<bluer::rfcomm::ProfileHandle, bluer::Error> {
596 self.session.register_profile(profile).await
597 }
598
599 fn build_agent(
601 s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
602 ) -> bluer::agent::Agent {
603 let mut blue_agent = bluer::agent::Agent::default();
604 blue_agent.request_default = true;
605 blue_agent.request_pin_code = None;
606 blue_agent.request_passkey = None;
607 let s2 = s.clone();
608 blue_agent.display_passkey = Some(Box::new(move |mut a| {
609 println!("Running process for display_passkey: {:?}", a);
610 let s3 = s2.clone();
611 async move {
612 let mut chan = tokio::sync::mpsc::channel(5);
613 let _ = s3
614 .send(super::MessageToBluetoothHost::DisplayPasskey(a.passkey, chan.0))
615 .await;
616 loop {
617 let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
618 tokio::select! {
619 asdf = f => {
620 match asdf {
621 Ok(Some(m)) => match m {
622 super::ResponseToPasskey::Yes => {
623 let _ = s3
624 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
625 .await;
626 return Ok(());
627 }
628 super::ResponseToPasskey::No => {
629 let _ = s3
630 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
631 .await;
632 return Err(bluer::agent::ReqError::Rejected);
633 }
634 super::ResponseToPasskey::Cancel => {
635 let _ = s3
636 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
637 .await;
638 return Err(bluer::agent::ReqError::Canceled);
639 }
640 super::ResponseToPasskey::Waiting => {}
641 },
642 Ok(None) => {}
643 _ => {
644 let _ = s3
645 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
646 .await;
647 return Err(bluer::agent::ReqError::Canceled);
648 }
649 }
650 }
651 _ = &mut a.cancel => {
652 let _ = s3
653 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
654 .await;
655 break Err(bluer::agent::ReqError::Canceled);
656 }
657 }
658 }
659 }
660 .boxed()
661 }));
662 blue_agent.display_pin_code = Some(Box::new(|a| {
663 async move {
664 println!("Need to display pin code {:?}", a);
665 a.cancel.await.unwrap();
666 Ok(())
667 }
668 .boxed()
669 }));
670 let s2 = s.clone();
671 blue_agent.request_confirmation = Some(Box::new(move |a| {
672 println!("Need to confirm {:?}", a);
673 let s3 = s2.clone();
674 async move {
675 let mut chan = tokio::sync::mpsc::channel(5);
676 let _ = s3
677 .send(super::MessageToBluetoothHost::ConfirmPasskey(
678 a.passkey, chan.0,
679 ))
680 .await;
681 loop {
682 let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
683 let asdf = f.await;
684 match asdf {
685 Ok(Some(m)) => match m {
686 super::ResponseToPasskey::Yes => {
687 let _ = s3
688 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
689 .await;
690 return Ok(());
691 }
692 super::ResponseToPasskey::No => {
693 let _ = s3
694 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
695 .await;
696 return Err(bluer::agent::ReqError::Rejected);
697 }
698 super::ResponseToPasskey::Cancel => {
699 let _ = s3
700 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
701 .await;
702 return Err(bluer::agent::ReqError::Canceled);
703 }
704 super::ResponseToPasskey::Waiting => {}
705 },
706 Ok(None) => {}
707 _ => {
708 let _ = s3
709 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
710 .await;
711 return Err(bluer::agent::ReqError::Canceled);
712 }
713 }
714 }
715 }
716 .boxed()
717 }));
718 blue_agent.request_authorization = Some(Box::new(|a| {
719 async move {
720 println!("Need to authorize {:?}", a);
721 Ok(())
722 }
723 .boxed()
724 }));
725 blue_agent.authorize_service = Some(Box::new(|a| {
726 async move {
727 println!("Need to authorize service {:?}", a);
728 Ok(())
729 }
730 .boxed()
731 }));
732 blue_agent
733 }
734
735 pub async fn issue_command(
737 &mut self,
738 cmd: super::BluetoothCommand,
739 ) -> Option<super::BluetoothResponse> {
740 match cmd {
741 super::BluetoothCommand::QueryNumAdapters => {
742 Some(super::BluetoothResponse::Adapters(self.adapters.len()))
743 }
744 _ => None,
745 }
746 }
747
748 pub async fn scan<'a>(
751 &'a mut self,
752 bluetooth_devices: &mut HashMap<
753 bluer::Address,
754 (&'a bluer::Adapter, Option<bluer::Device>),
755 >,
756 ) {
757 let mut adapter_scanner = Vec::new();
758 for a in &self.adapters {
759 let da = a.discover_devices_with_changes().await.unwrap();
760 adapter_scanner.push((a, da));
761 }
762
763 for (adapt, da) in &mut adapter_scanner {
764 if let Some(e) = da.next().await {
765 match e {
766 AdapterEvent::DeviceAdded(addr) => {
767 log::debug!("Device added {:?}", addr);
768 bluetooth_devices.insert(addr, (adapt, None));
769 }
770 AdapterEvent::DeviceRemoved(addr) => {
771 log::debug!("Device removed {:?}", addr);
772 bluetooth_devices.remove_entry(&addr);
773 }
774 AdapterEvent::PropertyChanged(prop) => {
775 log::debug!("Adapter property changed {:?}", prop);
776 }
777 }
778 }
779 }
780
781 for (addr, (adapter, dev)) in bluetooth_devices.iter_mut() {
782 if dev.is_none() {
783 if let Ok(d) = adapter.device(*addr) {
784 if let Ok(ps) = d.all_properties().await {
785 for p in ps {
786 log::debug!("Device {:?} property: {:?}", addr, p);
787 }
788 }
789 *dev = Some(d);
790 }
791 }
792 }
793 }
794}