1use std::collections::{BTreeMap, HashMap};
4
5use bluer::AdapterEvent;
6use futures::FutureExt;
7use futures::StreamExt;
8
9impl super::BluetoothRfcommConnectableAsyncTrait for bluer::rfcomm::ConnectRequest {
14 async fn accept(self) -> Result<crate::BluetoothStream, String> {
15 bluer::rfcomm::ConnectRequest::accept(self)
16 .map(|a| crate::BluetoothStream::Bluez(Box::pin(a)))
17 .map_err(|e| e.to_string())
18 }
19}
20
21impl super::BluetoothRfcommProfileAsyncTrait for bluer::rfcomm::ProfileHandle {
26 async fn connectable(&mut self) -> Result<crate::BluetoothRfcommConnectableAsync, String> {
27 self.next()
28 .await
29 .map(|a| crate::BluetoothRfcommConnectableAsync::Bluez(a))
30 .ok_or_else(|| "Failed to get bluetooth connection".to_string())
31 }
32}
33
34enum BluetoothConnection {
40 Rfcomm(bluer::rfcomm::Stream),
42 L2cap(bluer::l2cap::Stream),
44}
45
46impl std::io::Read for BluetoothConnection {
47 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
48 tokio::task::block_in_place(|| {
49 tokio::runtime::Handle::current().block_on(async {
50 use tokio::io::AsyncReadExt;
51 match self {
52 BluetoothConnection::Rfcomm(s) => s.read(buf).await,
53 BluetoothConnection::L2cap(s) => s.read(buf).await,
54 }
55 })
56 })
57 }
58}
59
60impl std::io::Write for BluetoothConnection {
61 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
62 tokio::task::block_in_place(|| {
63 tokio::runtime::Handle::current().block_on(async {
64 use tokio::io::AsyncWriteExt;
65 match self {
66 BluetoothConnection::Rfcomm(s) => s.write(buf).await,
67 BluetoothConnection::L2cap(s) => s.write(buf).await,
68 }
69 })
70 })
71 }
72
73 fn flush(&mut self) -> std::io::Result<()> {
74 tokio::task::block_in_place(|| {
75 tokio::runtime::Handle::current().block_on(async {
76 use tokio::io::AsyncWriteExt;
77 match self {
78 BluetoothConnection::Rfcomm(s) => s.flush().await,
79 BluetoothConnection::L2cap(s) => s.flush().await,
80 }
81 })
82 })
83 }
84}
85
86pub struct BluetoothRfcommSocket {
94 device_addr: bluer::Address,
96 rfcomm_channel: Option<u8>,
104 l2cap_psm: Option<u16>,
106 is_secure: bool,
108 connection: Option<BluetoothConnection>,
110}
111
112impl BluetoothRfcommSocket {
113 fn new_rfcomm(device_addr: bluer::Address, channel: u8, is_secure: bool) -> Self {
115 Self {
116 device_addr,
117 rfcomm_channel: Some(channel),
118 l2cap_psm: None,
119 is_secure,
120 connection: None,
121 }
122 }
123
124 fn new_l2cap(device_addr: bluer::Address, psm: u16, is_secure: bool) -> Self {
126 Self {
127 device_addr,
128 rfcomm_channel: None,
129 l2cap_psm: Some(psm),
130 is_secure,
131 connection: None,
132 }
133 }
134}
135
136impl crate::BluetoothSocketTrait for &mut BluetoothRfcommSocket {
137 fn is_connected(&self) -> Result<bool, std::io::Error> {
138 Ok(self.connection.is_some())
139 }
140
141 fn connect(&mut self) -> Result<(), std::io::Error> {
142 if self.connection.is_some() {
143 return Ok(());
144 }
145 tokio::task::block_in_place(|| {
146 tokio::runtime::Handle::current().block_on(async {
147 if let Some(channel) = self.rfcomm_channel {
148 let addr = bluer::rfcomm::SocketAddr::new(self.device_addr, channel);
149 let socket = bluer::rfcomm::Socket::new()
150 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
151 if self.is_secure {
152 socket
153 .set_security(bluer::rfcomm::Security {
154 level: bluer::rfcomm::SecurityLevel::Medium,
155 key_size: 0,
156 })
157 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
158 }
159 let stream = socket
160 .connect(addr)
161 .await
162 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
163 self.connection = Some(BluetoothConnection::Rfcomm(stream));
164 } else if let Some(psm) = self.l2cap_psm {
165 let addr = bluer::l2cap::SocketAddr::new(
166 self.device_addr,
167 bluer::AddressType::BrEdr,
168 psm,
169 );
170 let socket = bluer::l2cap::Socket::<bluer::l2cap::Stream>::new_stream()
171 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
172 if self.is_secure {
173 socket
174 .set_security(bluer::l2cap::Security {
175 level: bluer::l2cap::SecurityLevel::Medium,
176 key_size: 0,
177 })
178 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
179 }
180 let stream = socket
181 .connect(addr)
182 .await
183 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
184 self.connection = Some(BluetoothConnection::L2cap(stream));
185 } else {
186 return Err(std::io::Error::new(
187 std::io::ErrorKind::InvalidInput,
188 "BluetoothRfcommSocket has neither an RFCOMM channel nor an L2CAP PSM configured",
189 ));
190 }
191 Ok(())
192 })
193 })
194 }
195}
196
197impl std::io::Read for BluetoothRfcommSocket {
198 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
199 match &mut self.connection {
200 Some(conn) => conn.read(buf),
201 None => Err(std::io::Error::from(std::io::ErrorKind::NotConnected)),
202 }
203 }
204}
205
206impl std::io::Write for BluetoothRfcommSocket {
207 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
208 match &mut self.connection {
209 Some(conn) => conn.write(buf),
210 None => Err(std::io::Error::from(std::io::ErrorKind::NotConnected)),
211 }
212 }
213
214 fn flush(&mut self) -> std::io::Result<()> {
215 match &mut self.connection {
216 Some(conn) => conn.flush(),
217 None => Err(std::io::Error::from(std::io::ErrorKind::NotConnected)),
218 }
219 }
220}
221
222pub struct LinuxBluetoothDevice {
230 device: bluer::Device,
232 sockets: BTreeMap<String, BluetoothRfcommSocket>,
234}
235
236impl LinuxBluetoothDevice {
237 pub fn new(device: bluer::Device) -> Self {
239 Self {
240 device,
241 sockets: BTreeMap::new(),
242 }
243 }
244}
245
246impl super::BluetoothDeviceTrait for LinuxBluetoothDevice {
247 fn run_sdp(&mut self) {
254 let device = self.device.clone();
255 let _ = tokio::task::block_in_place(|| {
256 tokio::runtime::Handle::current().block_on(async move { device.connect().await })
257 });
258 }
259
260 fn get_uuids(&mut self) -> Result<Vec<crate::BluetoothUuid>, std::io::Error> {
261 tokio::task::block_in_place(|| {
262 tokio::runtime::Handle::current().block_on(async {
263 let uuids = self
264 .device
265 .uuids()
266 .await
267 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
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(&mut self) -> Option<&mut dyn super::AsyncBluetoothAdapterTrait> {
468 Some(self)
469 }
470
471 fn supports_sync(&mut self) -> Option<&mut 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(dev)));
530 }
531 }
532 }
533 Some(list)
534 }
535
536 async fn addresses(&self) -> Vec<super::BluetoothAdapterAddress> {
537 let mut a = Vec::new();
538 for adapter in &self.adapters {
539 if let Ok(adr) = adapter.address().await {
540 a.push(super::BluetoothAdapterAddress::Byte(adr.0));
541 }
542 }
543 a
544 }
545
546 async fn set_discoverable(&self, d: bool) -> Result<(), ()> {
547 for adapter in &self.adapters {
548 adapter.set_discoverable(d).await.map_err(|_| ())?;
549 }
550 Ok(())
551 }
552}
553
554impl BluetoothHandler {
555 pub async fn addresses(&self) -> Vec<bluer::Address> {
557 let mut addrs = Vec::new();
558 for a in &self.adapters {
559 if let Ok(addr) = a.address().await {
560 addrs.push(addr);
561 }
562 }
563 addrs
564 }
565
566 pub async fn new(
568 s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
569 ) -> Result<Self, String> {
570 let session = bluer::Session::new().await.map_err(|e| e.to_string())?;
571
572 let adapter_names = session.adapter_names().await.map_err(|e| e.to_string())?;
573 let adapters: Vec<bluer::Adapter> = adapter_names
574 .iter()
575 .filter_map(|n| session.adapter(n).ok())
576 .collect();
577
578 let blue_agent = Self::build_agent(s);
579 let blue_agent_handle = session.register_agent(blue_agent).await;
580 println!("Registered a bluetooth agent {}", blue_agent_handle.is_ok());
581 Ok(Self {
582 session,
583 adapters,
584 _blue_agent_handle: blue_agent_handle.map_err(|e| e.to_string())?,
585 })
586 }
587
588 async fn enable(&mut self) {
590 for adapter in &self.adapters {
591 adapter.set_powered(true).await.unwrap();
592 adapter.set_pairable(true).await.unwrap();
593 }
594 }
595
596 async fn disable(&mut self) {
598 self.set_discoverable(false).await;
599 for adapter in &self.adapters {
600 adapter.set_powered(false).await.unwrap();
601 adapter.set_pairable(false).await.unwrap();
602 }
603 }
604
605 pub async fn set_discoverable(&mut self, d: bool) {
607 for adapter in &self.adapters {
608 adapter.set_discoverable(d).await.unwrap();
609 }
610 }
611
612 pub async fn register_rfcomm_profile(
614 &mut self,
615 profile: bluer::rfcomm::Profile,
616 ) -> Result<bluer::rfcomm::ProfileHandle, bluer::Error> {
617 self.session.register_profile(profile).await
618 }
619
620 fn build_agent(
622 s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
623 ) -> bluer::agent::Agent {
624 let mut blue_agent = bluer::agent::Agent::default();
625 blue_agent.request_default = true;
626 blue_agent.request_pin_code = None;
627 blue_agent.request_passkey = None;
628 let s2 = s.clone();
629 blue_agent.display_passkey = Some(Box::new(move |mut a| {
630 println!("Running process for display_passkey: {:?}", a);
631 let s3 = s2.clone();
632 async move {
633 let mut chan = tokio::sync::mpsc::channel(5);
634 let _ = s3
635 .send(super::MessageToBluetoothHost::DisplayPasskey(a.passkey, chan.0))
636 .await;
637 loop {
638 let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
639 tokio::select! {
640 asdf = f => {
641 match asdf {
642 Ok(Some(m)) => match m {
643 super::ResponseToPasskey::Yes => {
644 let _ = s3
645 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
646 .await;
647 return Ok(());
648 }
649 super::ResponseToPasskey::No => {
650 let _ = s3
651 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
652 .await;
653 return Err(bluer::agent::ReqError::Rejected);
654 }
655 super::ResponseToPasskey::Cancel => {
656 let _ = s3
657 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
658 .await;
659 return Err(bluer::agent::ReqError::Canceled);
660 }
661 super::ResponseToPasskey::Waiting => {}
662 },
663 Ok(None) => {}
664 _ => {
665 let _ = s3
666 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
667 .await;
668 return Err(bluer::agent::ReqError::Canceled);
669 }
670 }
671 }
672 _ = &mut a.cancel => {
673 let _ = s3
674 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
675 .await;
676 break Err(bluer::agent::ReqError::Canceled);
677 }
678 }
679 }
680 }
681 .boxed()
682 }));
683 blue_agent.display_pin_code = Some(Box::new(|a| {
684 async move {
685 println!("Need to display pin code {:?}", a);
686 a.cancel.await.unwrap();
687 Ok(())
688 }
689 .boxed()
690 }));
691 let s2 = s.clone();
692 blue_agent.request_confirmation = Some(Box::new(move |a| {
693 println!("Need to confirm {:?}", a);
694 let s3 = s2.clone();
695 async move {
696 let mut chan = tokio::sync::mpsc::channel(5);
697 let _ = s3
698 .send(super::MessageToBluetoothHost::ConfirmPasskey(
699 a.passkey, chan.0,
700 ))
701 .await;
702 loop {
703 let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
704 let asdf = f.await;
705 match asdf {
706 Ok(Some(m)) => match m {
707 super::ResponseToPasskey::Yes => {
708 let _ = s3
709 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
710 .await;
711 return Ok(());
712 }
713 super::ResponseToPasskey::No => {
714 let _ = s3
715 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
716 .await;
717 return Err(bluer::agent::ReqError::Rejected);
718 }
719 super::ResponseToPasskey::Cancel => {
720 let _ = s3
721 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
722 .await;
723 return Err(bluer::agent::ReqError::Canceled);
724 }
725 super::ResponseToPasskey::Waiting => {}
726 },
727 Ok(None) => {}
728 _ => {
729 let _ = s3
730 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
731 .await;
732 return Err(bluer::agent::ReqError::Canceled);
733 }
734 }
735 }
736 }
737 .boxed()
738 }));
739 blue_agent.request_authorization = Some(Box::new(|a| {
740 async move {
741 println!("Need to authorize {:?}", a);
742 Ok(())
743 }
744 .boxed()
745 }));
746 blue_agent.authorize_service = Some(Box::new(|a| {
747 async move {
748 println!("Need to authorize service {:?}", a);
749 Ok(())
750 }
751 .boxed()
752 }));
753 blue_agent
754 }
755
756 pub async fn issue_command(
758 &mut self,
759 cmd: super::BluetoothCommand,
760 ) -> Option<super::BluetoothResponse> {
761 match cmd {
762 super::BluetoothCommand::QueryNumAdapters => {
763 Some(super::BluetoothResponse::Adapters(self.adapters.len()))
764 }
765 _ => None,
766 }
767 }
768
769 pub async fn scan<'a>(
772 &'a mut self,
773 bluetooth_devices: &mut HashMap<
774 bluer::Address,
775 (&'a bluer::Adapter, Option<bluer::Device>),
776 >,
777 ) {
778 let mut adapter_scanner = Vec::new();
779 for a in &self.adapters {
780 let da = a.discover_devices_with_changes().await.unwrap();
781 adapter_scanner.push((a, da));
782 }
783
784 for (adapt, da) in &mut adapter_scanner {
785 if let Some(e) = da.next().await {
786 match e {
787 AdapterEvent::DeviceAdded(addr) => {
788 log::debug!("Device added {:?}", addr);
789 bluetooth_devices.insert(addr, (adapt, None));
790 }
791 AdapterEvent::DeviceRemoved(addr) => {
792 log::debug!("Device removed {:?}", addr);
793 bluetooth_devices.remove_entry(&addr);
794 }
795 AdapterEvent::PropertyChanged(prop) => {
796 log::debug!("Adapter property changed {:?}", prop);
797 }
798 }
799 }
800 }
801
802 for (addr, (adapter, dev)) in bluetooth_devices.iter_mut() {
803 if dev.is_none() {
804 if let Ok(d) = adapter.device(*addr) {
805 if let Ok(ps) = d.all_properties().await {
806 for p in ps {
807 log::debug!("Device {:?} property: {:?}", addr, p);
808 }
809 }
810 *dev = Some(d);
811 }
812 }
813 }
814 }
815}