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, 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 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 log::info!("STREAM {:?} to {:?}", stream.as_ref().local_addr(), stream.peer_addr());
165 self.connection = Some(BluetoothConnection::Rfcomm(stream));
166 log::info!("Got an rfcomm stream");
167 } else if let Some(psm) = self.l2cap_psm {
168 let addr = bluer::l2cap::SocketAddr::new(
169 self.device_addr,
170 bluer::AddressType::BrEdr,
171 psm,
172 );
173 let socket = bluer::l2cap::Socket::<bluer::l2cap::Stream>::new_stream()
174 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
175 if self.is_secure {
176 socket
177 .set_security(bluer::l2cap::Security {
178 level: bluer::l2cap::SecurityLevel::Medium,
179 key_size: 0,
180 })
181 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
182 }
183 let stream = socket
184 .connect(addr)
185 .await
186 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
187 self.connection = Some(BluetoothConnection::L2cap(stream));
188 } else {
189 return Err(std::io::Error::new(
190 std::io::ErrorKind::InvalidInput,
191 "BluetoothRfcommSocket has neither an RFCOMM channel nor an L2CAP PSM configured",
192 ));
193 }
194 Ok(())
195 })
196 })
197 }
198}
199
200impl std::io::Read for BluetoothRfcommSocket {
201 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
202 match &mut self.connection {
203 Some(conn) => conn.read(buf),
204 None => Err(std::io::Error::from(std::io::ErrorKind::NotConnected)),
205 }
206 }
207}
208
209impl std::io::Write for BluetoothRfcommSocket {
210 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
211 match &mut self.connection {
212 Some(conn) => conn.write(buf),
213 None => Err(std::io::Error::from(std::io::ErrorKind::NotConnected)),
214 }
215 }
216
217 fn flush(&mut self) -> std::io::Result<()> {
218 match &mut self.connection {
219 Some(conn) => conn.flush(),
220 None => Err(std::io::Error::from(std::io::ErrorKind::NotConnected)),
221 }
222 }
223}
224
225pub struct LinuxBluetoothDevice {
233 device: bluer::Device,
235}
236
237impl LinuxBluetoothDevice {
238 pub fn new(device: bluer::Device) -> Self {
240 Self { device }
241 }
242}
243
244impl super::BluetoothDeviceTrait for LinuxBluetoothDevice {
245 fn get_uuids(&mut self) -> Result<Vec<crate::BluetoothUuid>, std::io::Error> {
246 tokio::task::block_in_place(|| {
247 tokio::runtime::Handle::current().block_on(async {
248 let uuids =
249 self.device.uuids().await.map_err(|e| {
250 std::io::Error::new(std::io::ErrorKind::Other, e.to_string())
251 })?;
252 Ok(uuids
253 .unwrap_or_default()
254 .into_iter()
255 .map(|u| {
256 use std::str::FromStr;
257 crate::BluetoothUuid::from_str(&u.to_string())
258 .unwrap_or_else(|_| crate::BluetoothUuid::Unknown(u.to_string()))
259 })
260 .collect())
261 })
262 })
263 }
264
265 fn get_name(&self) -> Result<String, std::io::Error> {
268 let device = self.device.clone();
269 tokio::task::block_in_place(|| {
270 tokio::runtime::Handle::current().block_on(async move {
271 device
272 .alias()
273 .await
274 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
275 })
276 })
277 }
278
279 fn get_address(&mut self) -> Result<String, std::io::Error> {
280 Ok(self.device.address().to_string())
281 }
282
283 fn get_pair_state(&self) -> Result<crate::PairingStatus, 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 let paired = device
288 .is_paired()
289 .await
290 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
291 Ok(if paired {
292 crate::PairingStatus::Paired
293 } else {
294 crate::PairingStatus::NotPaired
295 })
296 })
297 })
298 }
299
300 fn get_l2cap_socket(
309 &mut self,
310 psm: u16,
311 is_secure: bool,
312 ) -> Result<crate::BluetoothSocket, String> {
313 let addr = self.device.address();
314 let socket = BluetoothRfcommSocket::new_l2cap(addr, psm, is_secure);
315 Ok(crate::BluetoothSocket::Bluez(socket))
316 }
317
318 fn get_rfcomm_socket(
327 &mut self,
328 channel: u8,
329 is_secure: bool,
330 ) -> Result<crate::BluetoothSocket, String> {
331 let addr = self.device.address();
332 let socket = BluetoothRfcommSocket::new_rfcomm(addr, channel, is_secure);
333 Ok(crate::BluetoothSocket::Bluez(socket))
334 }
335}
336
337pub struct BluetoothDiscovery {}
343
344impl BluetoothDiscovery {
345 fn new() -> Self {
347 Self {}
348 }
349}
350
351impl super::BluetoothDiscoveryTrait for BluetoothDiscovery {}
352
353impl Drop for BluetoothDiscovery {
354 fn drop(&mut self) {}
355}
356
357impl TryFrom<super::BluetoothRfcommProfileSettings> for bluer::rfcomm::Profile {
362 type Error = String;
363 fn try_from(value: super::BluetoothRfcommProfileSettings) -> Result<Self, Self::Error> {
364 let service = if let Some(v) = value.service_uuid {
365 Some(bluer::Uuid::parse_str(&v).map_err(|e| e.to_string())?)
366 } else {
367 None
368 };
369 Ok(Self {
370 uuid: bluer::Uuid::parse_str(&value.uuid).map_err(|e| e.to_string())?,
371 name: value.name,
372 service,
373 role: if value.channel.is_some() {
374 Some(bluer::rfcomm::Role::Server)
375 } else {
376 None
377 },
378 channel: value.channel,
379 psm: value.psm,
380 require_authentication: value.authenticate,
381 require_authorization: value.authorize,
382 auto_connect: value.auto_connect,
383 service_record: value.sdp_record,
384 version: value.sdp_version,
385 features: value.sdp_features,
386 ..Default::default()
387 })
388 }
389}
390
391impl TryFrom<super::BluetoothL2capProfileSettings> for bluer::rfcomm::Profile {
395 type Error = String;
396 fn try_from(value: super::BluetoothL2capProfileSettings) -> Result<Self, Self::Error> {
397 let service = if let Some(v) = value.service_uuid {
398 Some(bluer::Uuid::parse_str(&v).map_err(|e| e.to_string())?)
399 } else {
400 None
401 };
402 Ok(Self {
403 uuid: bluer::Uuid::parse_str(&value.uuid).map_err(|e| e.to_string())?,
404 name: value.name,
405 service,
406 role: None,
407 channel: None,
408 psm: value.psm,
409 require_authentication: value.authenticate,
410 require_authorization: value.authorize,
411 auto_connect: value.auto_connect,
412 service_record: value.sdp_record,
413 version: value.sdp_version,
414 features: value.sdp_features,
415 ..Default::default()
416 })
417 }
418}
419
420pub struct BluetoothHandler {
426 session: bluer::Session,
428 adapters: Vec<bluer::Adapter>,
430 _blue_agent_handle: bluer::agent::AgentHandle,
432}
433
434impl super::BluetoothAdapterTrait for BluetoothHandler {
435 fn supports_async(&self) -> Option<&dyn super::AsyncBluetoothAdapterTrait> {
436 Some(self)
437 }
438
439 fn supports_sync(&self) -> Option<&dyn super::SyncBluetoothAdapterTrait> {
440 None
441 }
442}
443
444#[async_trait::async_trait]
445impl super::AsyncBluetoothAdapterTrait for BluetoothHandler {
446 async fn register_rfcomm_profile(
447 &self,
448 settings: super::BluetoothRfcommProfileSettings,
449 ) -> Result<crate::BluetoothRfcommProfileAsync, String> {
450 self.session
451 .register_profile(settings.try_into()?)
452 .await
453 .map(|a| super::BluetoothRfcommProfileAsync::Bluez(a.into()))
454 .map_err(|e| e.to_string())
455 }
456
457 async fn register_l2cap_profile(
463 &self,
464 settings: super::BluetoothL2capProfileSettings,
465 ) -> Result<crate::BluetoothL2capProfileAsync, String> {
466 self.session
467 .register_profile(settings.try_into()?)
468 .await
469 .map(|a| super::BluetoothL2capProfileAsync::Bluez(a.into()))
470 .map_err(|e| e.to_string())
471 }
472
473 fn start_discovery(&self) -> crate::BluetoothDiscovery {
474 BluetoothDiscovery::new().into()
475 }
476
477 fn get_paired_devices(&self) -> Option<Vec<crate::BluetoothDevice>> {
479 let mut list = Vec::new();
480 for adapter in &self.adapters {
481 let result = tokio::task::block_in_place(|| {
482 tokio::runtime::Handle::current().block_on(async {
483 let addrs = adapter.device_addresses().await?;
484 let mut paired = Vec::new();
485 for addr in addrs {
486 if let Ok(dev) = adapter.device(addr) {
487 if dev.is_paired().await.unwrap_or(false) {
488 paired.push(dev);
489 }
490 }
491 }
492 Ok::<Vec<bluer::Device>, bluer::Error>(paired)
493 })
494 });
495 if let Ok(devices) = result {
496 for dev in devices {
497 list.push(crate::BluetoothDevice::Bluez(LinuxBluetoothDevice::new(
498 dev,
499 )));
500 }
501 }
502 }
503 Some(list)
504 }
505
506 async fn addresses(&self) -> Vec<super::BluetoothAdapterAddress> {
507 let mut a = Vec::new();
508 for adapter in &self.adapters {
509 if let Ok(adr) = adapter.address().await {
510 a.push(super::BluetoothAdapterAddress::Byte(adr.0));
511 }
512 }
513 a
514 }
515
516 async fn set_discoverable(&self, d: bool) -> Result<(), ()> {
517 for adapter in &self.adapters {
518 adapter.set_discoverable(d).await.map_err(|_| ())?;
519 }
520 Ok(())
521 }
522}
523
524impl BluetoothHandler {
525 pub async fn addresses(&self) -> Vec<bluer::Address> {
527 let mut addrs = Vec::new();
528 for a in &self.adapters {
529 if let Ok(addr) = a.address().await {
530 addrs.push(addr);
531 }
532 }
533 addrs
534 }
535
536 pub async fn new(
538 s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
539 ) -> Result<Self, String> {
540 let session = bluer::Session::new().await.map_err(|e| e.to_string())?;
541
542 let adapter_names = session.adapter_names().await.map_err(|e| e.to_string())?;
543 let adapters: Vec<bluer::Adapter> = adapter_names
544 .iter()
545 .filter_map(|n| session.adapter(n).ok())
546 .collect();
547
548 let blue_agent = Self::build_agent(s);
549 let blue_agent_handle = session.register_agent(blue_agent).await;
550 println!("Registered a bluetooth agent {}", blue_agent_handle.is_ok());
551 Ok(Self {
552 session,
553 adapters,
554 _blue_agent_handle: blue_agent_handle.map_err(|e| e.to_string())?,
555 })
556 }
557
558 async fn enable(&mut self) {
560 for adapter in &self.adapters {
561 adapter.set_powered(true).await.unwrap();
562 adapter.set_pairable(true).await.unwrap();
563 }
564 }
565
566 async fn disable(&mut self) {
568 self.set_discoverable(false).await;
569 for adapter in &self.adapters {
570 adapter.set_powered(false).await.unwrap();
571 adapter.set_pairable(false).await.unwrap();
572 }
573 }
574
575 pub async fn set_discoverable(&mut self, d: bool) {
577 for adapter in &self.adapters {
578 adapter.set_discoverable(d).await.unwrap();
579 }
580 }
581
582 pub async fn register_rfcomm_profile(
584 &mut self,
585 profile: bluer::rfcomm::Profile,
586 ) -> Result<bluer::rfcomm::ProfileHandle, bluer::Error> {
587 self.session.register_profile(profile).await
588 }
589
590 fn build_agent(
592 s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
593 ) -> bluer::agent::Agent {
594 let mut blue_agent = bluer::agent::Agent::default();
595 blue_agent.request_default = true;
596 blue_agent.request_pin_code = None;
597 blue_agent.request_passkey = None;
598 let s2 = s.clone();
599 blue_agent.display_passkey = Some(Box::new(move |mut a| {
600 println!("Running process for display_passkey: {:?}", a);
601 let s3 = s2.clone();
602 async move {
603 let mut chan = tokio::sync::mpsc::channel(5);
604 let _ = s3
605 .send(super::MessageToBluetoothHost::DisplayPasskey(a.passkey, chan.0))
606 .await;
607 loop {
608 let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
609 tokio::select! {
610 asdf = f => {
611 match asdf {
612 Ok(Some(m)) => match m {
613 super::ResponseToPasskey::Yes => {
614 let _ = s3
615 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
616 .await;
617 return Ok(());
618 }
619 super::ResponseToPasskey::No => {
620 let _ = s3
621 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
622 .await;
623 return Err(bluer::agent::ReqError::Rejected);
624 }
625 super::ResponseToPasskey::Cancel => {
626 let _ = s3
627 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
628 .await;
629 return Err(bluer::agent::ReqError::Canceled);
630 }
631 super::ResponseToPasskey::Waiting => {}
632 },
633 Ok(None) => {}
634 _ => {
635 let _ = s3
636 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
637 .await;
638 return Err(bluer::agent::ReqError::Canceled);
639 }
640 }
641 }
642 _ = &mut a.cancel => {
643 let _ = s3
644 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
645 .await;
646 break Err(bluer::agent::ReqError::Canceled);
647 }
648 }
649 }
650 }
651 .boxed()
652 }));
653 blue_agent.display_pin_code = Some(Box::new(|a| {
654 async move {
655 println!("Need to display pin code {:?}", a);
656 a.cancel.await.unwrap();
657 Ok(())
658 }
659 .boxed()
660 }));
661 let s2 = s.clone();
662 blue_agent.request_confirmation = Some(Box::new(move |a| {
663 println!("Need to confirm {:?}", a);
664 let s3 = s2.clone();
665 async move {
666 let mut chan = tokio::sync::mpsc::channel(5);
667 let _ = s3
668 .send(super::MessageToBluetoothHost::ConfirmPasskey(
669 a.passkey, chan.0,
670 ))
671 .await;
672 loop {
673 let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
674 let asdf = f.await;
675 match asdf {
676 Ok(Some(m)) => match m {
677 super::ResponseToPasskey::Yes => {
678 let _ = s3
679 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
680 .await;
681 return Ok(());
682 }
683 super::ResponseToPasskey::No => {
684 let _ = s3
685 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
686 .await;
687 return Err(bluer::agent::ReqError::Rejected);
688 }
689 super::ResponseToPasskey::Cancel => {
690 let _ = s3
691 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
692 .await;
693 return Err(bluer::agent::ReqError::Canceled);
694 }
695 super::ResponseToPasskey::Waiting => {}
696 },
697 Ok(None) => {}
698 _ => {
699 let _ = s3
700 .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
701 .await;
702 return Err(bluer::agent::ReqError::Canceled);
703 }
704 }
705 }
706 }
707 .boxed()
708 }));
709 blue_agent.request_authorization = Some(Box::new(|a| {
710 async move {
711 println!("Need to authorize {:?}", a);
712 Ok(())
713 }
714 .boxed()
715 }));
716 blue_agent.authorize_service = Some(Box::new(|a| {
717 async move {
718 println!("Need to authorize service {:?}", a);
719 Ok(())
720 }
721 .boxed()
722 }));
723 blue_agent
724 }
725
726 pub async fn issue_command(
728 &mut self,
729 cmd: super::BluetoothCommand,
730 ) -> Option<super::BluetoothResponse> {
731 match cmd {
732 super::BluetoothCommand::QueryNumAdapters => {
733 Some(super::BluetoothResponse::Adapters(self.adapters.len()))
734 }
735 _ => None,
736 }
737 }
738
739 pub async fn scan<'a>(
742 &'a mut self,
743 bluetooth_devices: &mut HashMap<
744 bluer::Address,
745 (&'a bluer::Adapter, Option<bluer::Device>),
746 >,
747 ) {
748 let mut adapter_scanner = Vec::new();
749 for a in &self.adapters {
750 let da = a.discover_devices_with_changes().await.unwrap();
751 adapter_scanner.push((a, da));
752 }
753
754 for (adapt, da) in &mut adapter_scanner {
755 if let Some(e) = da.next().await {
756 match e {
757 AdapterEvent::DeviceAdded(addr) => {
758 log::debug!("Device added {:?}", addr);
759 bluetooth_devices.insert(addr, (adapt, None));
760 }
761 AdapterEvent::DeviceRemoved(addr) => {
762 log::debug!("Device removed {:?}", addr);
763 bluetooth_devices.remove_entry(&addr);
764 }
765 AdapterEvent::PropertyChanged(prop) => {
766 log::debug!("Adapter property changed {:?}", prop);
767 }
768 }
769 }
770 }
771
772 for (addr, (adapter, dev)) in bluetooth_devices.iter_mut() {
773 if dev.is_none() {
774 if let Ok(d) = adapter.device(*addr) {
775 if let Ok(ps) = d.all_properties().await {
776 for p in ps {
777 log::debug!("Device {:?} property: {:?}", addr, p);
778 }
779 }
780 *dev = Some(d);
781 }
782 }
783 }
784 }
785}