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 =
264 self.device.uuids().await.map_err(|e| {
265 std::io::Error::new(std::io::ErrorKind::Other, e.to_string())
266 })?;
267 Ok(uuids
268 .unwrap_or_default()
269 .into_iter()
270 .map(|u| {
271 use std::str::FromStr;
272 crate::BluetoothUuid::from_str(&u.to_string())
273 .unwrap_or_else(|_| crate::BluetoothUuid::Unknown(u.to_string()))
274 })
275 .collect())
276 })
277 })
278 }
279
280 fn get_name(&self) -> Result<String, std::io::Error> {
283 let device = self.device.clone();
284 tokio::task::block_in_place(|| {
285 tokio::runtime::Handle::current().block_on(async move {
286 device
287 .alias()
288 .await
289 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
290 })
291 })
292 }
293
294 fn get_address(&mut self) -> Result<String, std::io::Error> {
295 Ok(self.device.address().to_string())
296 }
297
298 fn get_pair_state(&self) -> Result<crate::PairingStatus, std::io::Error> {
299 let device = self.device.clone();
300 tokio::task::block_in_place(|| {
301 tokio::runtime::Handle::current().block_on(async move {
302 let paired = device
303 .is_paired()
304 .await
305 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
306 Ok(if paired {
307 crate::PairingStatus::Paired
308 } else {
309 crate::PairingStatus::NotPaired
310 })
311 })
312 })
313 }
314
315 fn get_l2cap_socket(
324 &mut self,
325 uuid: crate::BluetoothUuid,
326 is_secure: bool,
327 ) -> Result<crate::BluetoothSocket<'_>, String> {
328 let uuid_str = uuid.as_str().to_string();
329 if !self.sockets.contains_key(&uuid_str) {
330 let psm: u16 = 1;
333 let addr = self.device.address();
334 let socket = BluetoothRfcommSocket::new_l2cap(addr, psm, is_secure);
335 self.sockets.insert(uuid_str.clone(), socket);
336 }
337 self.sockets
338 .get_mut(&uuid_str)
339 .map(|s| crate::BluetoothSocket::Bluez(s))
340 .ok_or_else(|| "Socket does not exist".to_string())
341 }
342
343 fn get_rfcomm_socket(
352 &mut self,
353 uuid: crate::BluetoothUuid,
354 is_secure: bool,
355 ) -> Result<crate::BluetoothSocket<'_>, String> {
356 let uuid_str = uuid.as_str().to_string();
357 if !self.sockets.contains_key(&uuid_str) {
358 let channel: u8 = 1;
361 let addr = self.device.address();
362 let socket = BluetoothRfcommSocket::new_rfcomm(addr, channel, is_secure);
363 self.sockets.insert(uuid_str.clone(), socket);
364 }
365 self.sockets
366 .get_mut(&uuid_str)
367 .map(|s| crate::BluetoothSocket::Bluez(s))
368 .ok_or_else(|| "Socket does not exist".to_string())
369 }
370}
371
372pub struct BluetoothDiscovery {}
378
379impl BluetoothDiscovery {
380 fn new() -> Self {
382 Self {}
383 }
384}
385
386impl super::BluetoothDiscoveryTrait for BluetoothDiscovery {}
387
388impl Drop for BluetoothDiscovery {
389 fn drop(&mut self) {}
390}
391
392impl TryFrom<super::BluetoothRfcommProfileSettings> for bluer::rfcomm::Profile {
397 type Error = String;
398 fn try_from(value: super::BluetoothRfcommProfileSettings) -> Result<Self, Self::Error> {
399 let service = if let Some(v) = value.service_uuid {
400 Some(bluer::Uuid::parse_str(&v).map_err(|e| e.to_string())?)
401 } else {
402 None
403 };
404 Ok(Self {
405 uuid: bluer::Uuid::parse_str(&value.uuid).map_err(|e| e.to_string())?,
406 name: value.name,
407 service,
408 role: None,
409 channel: value.channel,
410 psm: value.psm,
411 require_authentication: value.authenticate,
412 require_authorization: value.authorize,
413 auto_connect: value.auto_connect,
414 service_record: value.sdp_record,
415 version: value.sdp_version,
416 features: value.sdp_features,
417 ..Default::default()
418 })
419 }
420}
421
422impl TryFrom<super::BluetoothL2capProfileSettings> for bluer::rfcomm::Profile {
426 type Error = String;
427 fn try_from(value: super::BluetoothL2capProfileSettings) -> Result<Self, Self::Error> {
428 let service = if let Some(v) = value.service_uuid {
429 Some(bluer::Uuid::parse_str(&v).map_err(|e| e.to_string())?)
430 } else {
431 None
432 };
433 Ok(Self {
434 uuid: bluer::Uuid::parse_str(&value.uuid).map_err(|e| e.to_string())?,
435 name: value.name,
436 service,
437 role: None,
438 channel: None,
439 psm: value.psm,
440 require_authentication: value.authenticate,
441 require_authorization: value.authorize,
442 auto_connect: value.auto_connect,
443 service_record: value.sdp_record,
444 version: value.sdp_version,
445 features: value.sdp_features,
446 ..Default::default()
447 })
448 }
449}
450
451pub struct BluetoothHandler {
457 session: bluer::Session,
459 adapters: Vec<bluer::Adapter>,
461 _blue_agent_handle: bluer::agent::AgentHandle,
463}
464
465impl super::BluetoothAdapterTrait for BluetoothHandler {
466 fn supports_async(&mut self) -> Option<&mut dyn super::AsyncBluetoothAdapterTrait> {
467 Some(self)
468 }
469
470 fn supports_sync(&mut self) -> Option<&mut dyn super::SyncBluetoothAdapterTrait> {
471 None
472 }
473}
474
475#[async_trait::async_trait]
476impl super::AsyncBluetoothAdapterTrait for BluetoothHandler {
477 async fn register_rfcomm_profile(
478 &self,
479 settings: super::BluetoothRfcommProfileSettings,
480 ) -> Result<crate::BluetoothRfcommProfileAsync, String> {
481 self.session
482 .register_profile(settings.try_into()?)
483 .await
484 .map(|a| super::BluetoothRfcommProfileAsync::Bluez(a.into()))
485 .map_err(|e| e.to_string())
486 }
487
488 async fn register_l2cap_profile(
494 &self,
495 settings: super::BluetoothL2capProfileSettings,
496 ) -> Result<crate::BluetoothL2capProfileAsync, String> {
497 self.session
498 .register_profile(settings.try_into()?)
499 .await
500 .map(|a| super::BluetoothL2capProfileAsync::Bluez(a.into()))
501 .map_err(|e| e.to_string())
502 }
503
504 fn start_discovery(&self) -> crate::BluetoothDiscovery {
505 BluetoothDiscovery::new().into()
506 }
507
508 fn get_paired_devices(&self) -> Option<Vec<crate::BluetoothDevice>> {
510 let mut list = Vec::new();
511 for adapter in &self.adapters {
512 let result = tokio::task::block_in_place(|| {
513 tokio::runtime::Handle::current().block_on(async {
514 let addrs = adapter.device_addresses().await?;
515 let mut paired = Vec::new();
516 for addr in addrs {
517 if let Ok(dev) = adapter.device(addr) {
518 if dev.is_paired().await.unwrap_or(false) {
519 paired.push(dev);
520 }
521 }
522 }
523 Ok::<Vec<bluer::Device>, bluer::Error>(paired)
524 })
525 });
526 if let Ok(devices) = result {
527 for dev in devices {
528 list.push(crate::BluetoothDevice::Bluez(LinuxBluetoothDevice::new(
529 dev,
530 )));
531 }
532 }
533 }
534 Some(list)
535 }
536
537 async fn addresses(&self) -> Vec<super::BluetoothAdapterAddress> {
538 let mut a = Vec::new();
539 for adapter in &self.adapters {
540 if let Ok(adr) = adapter.address().await {
541 a.push(super::BluetoothAdapterAddress::Byte(adr.0));
542 }
543 }
544 a
545 }
546
547 async fn set_discoverable(&self, d: bool) -> Result<(), ()> {
548 for adapter in &self.adapters {
549 adapter.set_discoverable(d).await.map_err(|_| ())?;
550 }
551 Ok(())
552 }
553}
554
555impl BluetoothHandler {
556 pub async fn addresses(&self) -> Vec<bluer::Address> {
558 let mut addrs = Vec::new();
559 for a in &self.adapters {
560 if let Ok(addr) = a.address().await {
561 addrs.push(addr);
562 }
563 }
564 addrs
565 }
566
567 pub async fn new(
569 s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
570 ) -> Result<Self, String> {
571 let session = bluer::Session::new().await.map_err(|e| e.to_string())?;
572
573 let adapter_names = session.adapter_names().await.map_err(|e| e.to_string())?;
574 let adapters: Vec<bluer::Adapter> = adapter_names
575 .iter()
576 .filter_map(|n| session.adapter(n).ok())
577 .collect();
578
579 let blue_agent = Self::build_agent(s);
580 let blue_agent_handle = session.register_agent(blue_agent).await;
581 println!("Registered a bluetooth agent {}", blue_agent_handle.is_ok());
582 Ok(Self {
583 session,
584 adapters,
585 _blue_agent_handle: blue_agent_handle.map_err(|e| e.to_string())?,
586 })
587 }
588
589 async fn enable(&mut self) {
591 for adapter in &self.adapters {
592 adapter.set_powered(true).await.unwrap();
593 adapter.set_pairable(true).await.unwrap();
594 }
595 }
596
597 async fn disable(&mut self) {
599 self.set_discoverable(false).await;
600 for adapter in &self.adapters {
601 adapter.set_powered(false).await.unwrap();
602 adapter.set_pairable(false).await.unwrap();
603 }
604 }
605
606 pub async fn set_discoverable(&mut self, d: bool) {
608 for adapter in &self.adapters {
609 adapter.set_discoverable(d).await.unwrap();
610 }
611 }
612
613 pub async fn register_rfcomm_profile(
615 &mut self,
616 profile: bluer::rfcomm::Profile,
617 ) -> Result<bluer::rfcomm::ProfileHandle, bluer::Error> {
618 self.session.register_profile(profile).await
619 }
620
621 fn build_agent(
623 s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
624 ) -> bluer::agent::Agent {
625 let mut blue_agent = bluer::agent::Agent::default();
626 blue_agent.request_default = true;
627 blue_agent.request_pin_code = None;
628 blue_agent.request_passkey = None;
629 let s2 = s.clone();
630 blue_agent.display_passkey = Some(Box::new(move |mut a| {
631 println!("Running process for display_passkey: {:?}", a);
632 let s3 = s2.clone();
633 async move {
634 let mut chan = tokio::sync::mpsc::channel(5);
635 let _ = s3
636 .send(super::MessageToBluetoothHost::DisplayPasskey(a.passkey, chan.0))
637 .await;
638 loop {
639 let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
640 tokio::select! {
641 asdf = f => {
642 match asdf {
643 Ok(Some(m)) => match m {
644 super::ResponseToPasskey::Yes => {
645 let _ = s3
646 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
647 .await;
648 return Ok(());
649 }
650 super::ResponseToPasskey::No => {
651 let _ = s3
652 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
653 .await;
654 return Err(bluer::agent::ReqError::Rejected);
655 }
656 super::ResponseToPasskey::Cancel => {
657 let _ = s3
658 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
659 .await;
660 return Err(bluer::agent::ReqError::Canceled);
661 }
662 super::ResponseToPasskey::Waiting => {}
663 },
664 Ok(None) => {}
665 _ => {
666 let _ = s3
667 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
668 .await;
669 return Err(bluer::agent::ReqError::Canceled);
670 }
671 }
672 }
673 _ = &mut a.cancel => {
674 let _ = s3
675 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
676 .await;
677 break Err(bluer::agent::ReqError::Canceled);
678 }
679 }
680 }
681 }
682 .boxed()
683 }));
684 blue_agent.display_pin_code = Some(Box::new(|a| {
685 async move {
686 println!("Need to display pin code {:?}", a);
687 a.cancel.await.unwrap();
688 Ok(())
689 }
690 .boxed()
691 }));
692 let s2 = s.clone();
693 blue_agent.request_confirmation = Some(Box::new(move |a| {
694 println!("Need to confirm {:?}", a);
695 let s3 = s2.clone();
696 async move {
697 let mut chan = tokio::sync::mpsc::channel(5);
698 let _ = s3
699 .send(super::MessageToBluetoothHost::ConfirmPasskey(
700 a.passkey, chan.0,
701 ))
702 .await;
703 loop {
704 let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
705 let asdf = f.await;
706 match asdf {
707 Ok(Some(m)) => match m {
708 super::ResponseToPasskey::Yes => {
709 let _ = s3
710 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
711 .await;
712 return Ok(());
713 }
714 super::ResponseToPasskey::No => {
715 let _ = s3
716 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
717 .await;
718 return Err(bluer::agent::ReqError::Rejected);
719 }
720 super::ResponseToPasskey::Cancel => {
721 let _ = s3
722 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
723 .await;
724 return Err(bluer::agent::ReqError::Canceled);
725 }
726 super::ResponseToPasskey::Waiting => {}
727 },
728 Ok(None) => {}
729 _ => {
730 let _ = s3
731 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
732 .await;
733 return Err(bluer::agent::ReqError::Canceled);
734 }
735 }
736 }
737 }
738 .boxed()
739 }));
740 blue_agent.request_authorization = Some(Box::new(|a| {
741 async move {
742 println!("Need to authorize {:?}", a);
743 Ok(())
744 }
745 .boxed()
746 }));
747 blue_agent.authorize_service = Some(Box::new(|a| {
748 async move {
749 println!("Need to authorize service {:?}", a);
750 Ok(())
751 }
752 .boxed()
753 }));
754 blue_agent
755 }
756
757 pub async fn issue_command(
759 &mut self,
760 cmd: super::BluetoothCommand,
761 ) -> Option<super::BluetoothResponse> {
762 match cmd {
763 super::BluetoothCommand::QueryNumAdapters => {
764 Some(super::BluetoothResponse::Adapters(self.adapters.len()))
765 }
766 _ => None,
767 }
768 }
769
770 pub async fn scan<'a>(
773 &'a mut self,
774 bluetooth_devices: &mut HashMap<
775 bluer::Address,
776 (&'a bluer::Adapter, Option<bluer::Device>),
777 >,
778 ) {
779 let mut adapter_scanner = Vec::new();
780 for a in &self.adapters {
781 let da = a.discover_devices_with_changes().await.unwrap();
782 adapter_scanner.push((a, da));
783 }
784
785 for (adapt, da) in &mut adapter_scanner {
786 if let Some(e) = da.next().await {
787 match e {
788 AdapterEvent::DeviceAdded(addr) => {
789 log::debug!("Device added {:?}", addr);
790 bluetooth_devices.insert(addr, (adapt, None));
791 }
792 AdapterEvent::DeviceRemoved(addr) => {
793 log::debug!("Device removed {:?}", addr);
794 bluetooth_devices.remove_entry(&addr);
795 }
796 AdapterEvent::PropertyChanged(prop) => {
797 log::debug!("Adapter property changed {:?}", prop);
798 }
799 }
800 }
801 }
802
803 for (addr, (adapter, dev)) in bluetooth_devices.iter_mut() {
804 if dev.is_none() {
805 if let Ok(d) = adapter.device(*addr) {
806 if let Ok(ps) = d.all_properties().await {
807 for p in ps {
808 log::debug!("Device {:?} property: {:?}", addr, p);
809 }
810 }
811 *dev = Some(d);
812 }
813 }
814 }
815 }
816}