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