1use bt_common::core::{Address, AddressType};
6use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
7use futures::future::{ready, Ready};
8use futures::stream::{FusedStream, Stream};
9use parking_lot::Mutex;
10use std::collections::{HashMap, HashSet, VecDeque};
11use std::sync::Arc;
12use std::task::{Poll, Waker};
13
14use bt_common::{PeerId, Uuid};
15
16use crate::central::ScanResult;
17use crate::client::CharacteristicNotification;
18
19use crate::periodic_advertising::{PeriodicAdvertising, SyncReport};
20use crate::pii::GetPeerAddr;
21use crate::server::{
22 self, LocalService, NotificationType, ReadResponder, ServiceDefinition, WriteResponder,
23};
24use crate::{types::*, GattTypes, ServerTypes};
25
26#[derive(Default)]
27struct FakePeerServiceInner {
28 notifiers: HashMap<Handle, UnboundedSender<Result<CharacteristicNotification>>>,
30
31 characteristics: HashMap<Handle, (Characteristic, Vec<u8>)>,
34}
35
36#[derive(Clone)]
37pub struct FakePeerService {
38 inner: Arc<Mutex<FakePeerServiceInner>>,
39}
40
41impl FakePeerService {
42 pub fn new() -> Self {
43 Self { inner: Arc::new(Mutex::new(Default::default())) }
44 }
45
46 pub fn add_characteristic(&mut self, char: Characteristic, value: Vec<u8>) {
50 let mut lock = self.inner.lock();
51 let handle = char.handle;
52 lock.characteristics.insert(handle, (char, value.clone()));
53 if let Some(notifier) = lock.notifiers.get_mut(&handle) {
54 notifier
55 .unbounded_send(Ok(CharacteristicNotification {
56 handle,
57 value,
58 maybe_truncated: false,
59 }))
60 .expect("should succeed");
61 }
62 }
63
64 pub fn expect_characteristic_value(&mut self, handle: &Handle, value: Vec<u8>) {
67 let mut lock = self.inner.lock();
68 let Some(char) = lock.characteristics.get_mut(handle) else {
69 panic!("Can't find characteristic {handle:?} to set expected value");
70 };
71 char.1 = value;
72 }
73
74 pub fn notify(&self, handle: &Handle, notification: Result<CharacteristicNotification>) {
76 let mut lock = self.inner.lock();
77 if let Some(notifier) = lock.notifiers.get_mut(handle) {
78 notifier.unbounded_send(notification).expect("can send notification");
79 }
80 }
81
82 pub fn clear_notifier(&self, handle: &Handle) {
85 let mut lock = self.inner.lock();
86 let _ = lock.notifiers.remove(handle);
87 }
88}
89
90impl crate::client::PeerService<FakeTypes> for FakePeerService {
91 fn discover_characteristics(
92 &self,
93 uuid: Option<Uuid>,
94 ) -> <FakeTypes as GattTypes>::CharacteristicDiscoveryFut {
95 let lock = self.inner.lock();
96 let mut result = Vec::new();
97 for (_handle, (char, _value)) in &lock.characteristics {
98 match uuid {
99 Some(uuid) if uuid == char.uuid => result.push(char.clone()),
100 None => result.push(char.clone()),
101 _ => {}
102 }
103 }
104 ready(Ok(result))
105 }
106
107 fn read_characteristic<'a>(
108 &self,
109 handle: &Handle,
110 _offset: u16,
111 buf: &'a mut [u8],
112 ) -> <FakeTypes as GattTypes>::ReadFut<'a> {
113 let read_characteristics = &(*self.inner.lock()).characteristics;
114 let Some((_, value)) = read_characteristics.get(handle) else {
115 return ready(Err(Error::Gatt(GattError::InvalidHandle)));
116 };
117 buf[..value.len()].copy_from_slice(value.as_slice());
118 ready(Ok((value.len(), false)))
119 }
120
121 fn write_characteristic<'a>(
124 &self,
125 handle: &Handle,
126 _mode: WriteMode,
127 _offset: u16,
128 buf: &'a [u8],
129 ) -> <FakeTypes as GattTypes>::WriteFut<'a> {
130 let expected_characteristics = &(*self.inner.lock()).characteristics;
131 let Some((_, expected)) = expected_characteristics.get(handle) else {
133 panic!("Write operation to characteristic {handle:?} was not expected");
134 };
135 if buf.len() != expected.len() || &buf[..expected.len()] != expected.as_slice() {
137 panic!("Value written to characteristic {handle:?} was not expected: {buf:?}");
138 }
139 ready(Ok(()))
140 }
141
142 fn read_descriptor<'a>(
143 &self,
144 _handle: &Handle,
145 _offset: u16,
146 _buf: &'a mut [u8],
147 ) -> <FakeTypes as GattTypes>::ReadFut<'a> {
148 todo!()
149 }
150
151 fn write_descriptor<'a>(
152 &self,
153 _handle: &Handle,
154 _offset: u16,
155 _buf: &'a [u8],
156 ) -> <FakeTypes as GattTypes>::WriteFut<'a> {
157 todo!()
158 }
159
160 fn subscribe(&self, handle: &Handle) -> <FakeTypes as GattTypes>::NotificationStream {
161 let (sender, receiver) = unbounded();
162 (*self.inner.lock()).notifiers.insert(*handle, sender);
163 receiver
164 }
165}
166
167#[derive(Clone)]
168pub struct FakeServiceHandle {
169 pub uuid: Uuid,
170 pub is_primary: bool,
171 pub fake_service: FakePeerService,
172}
173
174impl crate::client::PeerServiceHandle<FakeTypes> for FakeServiceHandle {
175 fn uuid(&self) -> Uuid {
176 self.uuid
177 }
178
179 fn is_primary(&self) -> bool {
180 self.is_primary
181 }
182
183 fn connect(&self) -> <FakeTypes as GattTypes>::ServiceConnectFut {
184 futures::future::ready(Ok(self.fake_service.clone()))
185 }
186}
187
188#[derive(Default)]
189struct FakeClientInner {
190 fake_services: Vec<FakeServiceHandle>,
191}
192
193#[derive(Clone)]
194pub struct FakeClient {
195 inner: Arc<Mutex<FakeClientInner>>,
196}
197
198impl FakeClient {
199 pub fn new() -> Self {
200 FakeClient { inner: Arc::new(Mutex::new(FakeClientInner::default())) }
201 }
202
203 pub fn add_service(&mut self, uuid: Uuid, is_primary: bool, fake_service: FakePeerService) {
205 self.inner.lock().fake_services.push(FakeServiceHandle { uuid, is_primary, fake_service });
206 }
207}
208
209impl crate::Client<FakeTypes> for FakeClient {
210 fn peer_id(&self) -> PeerId {
211 todo!()
212 }
213
214 fn find_service(&self, uuid: Uuid) -> <FakeTypes as GattTypes>::FindServicesFut {
215 let fake_services = &self.inner.lock().fake_services;
216 let mut filtered_services = Vec::new();
217 for handle in fake_services {
218 if handle.uuid == uuid {
219 filtered_services.push(handle.clone());
220 }
221 }
222
223 futures::future::ready(Ok(filtered_services))
224 }
225}
226
227#[derive(Default, Debug)]
228struct ScannedResultStreamInner {
229 results: VecDeque<Result<ScanResult>>,
230 waker: Option<Waker>,
231}
232
233#[derive(Clone, Debug, Default)]
234pub struct ScannedResultStreamController(Arc<Mutex<ScannedResultStreamInner>>);
235
236impl ScannedResultStreamController {
237 pub fn add_scanned_result(&self, item: Result<ScanResult>) {
239 let mut lock = self.0.lock();
240 lock.results.push_back(item);
241 if let Some(waker) = lock.waker.take() {
242 waker.wake();
243 }
244 }
245}
246
247#[derive(Debug, Default)]
248pub struct ScannedResultStream {
249 inner: Arc<Mutex<ScannedResultStreamInner>>,
250}
251
252impl ScannedResultStream {
253 pub fn new() -> Self {
257 Self::default()
258 }
259
260 pub fn controller(&self) -> ScannedResultStreamController {
261 ScannedResultStreamController(self.inner.clone())
262 }
263}
264
265impl FusedStream for ScannedResultStream {
266 fn is_terminated(&self) -> bool {
267 self.inner.lock().results.is_empty()
268 }
269}
270
271impl Stream for ScannedResultStream {
272 type Item = Result<ScanResult>;
273
274 fn poll_next(
275 self: std::pin::Pin<&mut Self>,
276 cx: &mut std::task::Context<'_>,
277 ) -> Poll<Option<Self::Item>> {
278 let mut lock = self.inner.lock();
279 match lock.results.pop_front() {
280 Some(result) => Poll::Ready(Some(result)),
281 None => {
282 lock.waker = Some(cx.waker().clone());
283 Poll::Pending
284 }
285 }
286 }
287}
288
289pub struct FakeGetPeerAddr;
292
293impl GetPeerAddr for FakeGetPeerAddr {
294 async fn get_peer_address(&self, peer_id: PeerId) -> Result<(Address, AddressType)> {
295 Ok((
296 [
297 peer_id.0 as u8,
298 ((peer_id.0 >> 8) & 0xff) as u8,
299 ((peer_id.0 >> 16) & 0xff) as u8,
300 ((peer_id.0 >> 24) & 0xff) as u8,
301 ((peer_id.0 >> 32) & 0xff) as u8,
302 ((peer_id.0 >> 48) & 0xff) as u8,
303 ],
304 AddressType::Public,
305 ))
306 }
307}
308
309pub struct FakeTypes {}
310
311impl GattTypes for FakeTypes {
312 type Central = FakeCentral;
313 type ScanResultStream = ScannedResultStream;
314 type Client = FakeClient;
315 type ConnectFuture = Ready<Result<FakeClient>>;
316 type PeerServiceHandle = FakeServiceHandle;
317 type FindServicesFut = Ready<Result<Vec<FakeServiceHandle>>>;
318 type PeerService = FakePeerService;
319 type ServiceConnectFut = Ready<Result<FakePeerService>>;
320 type CharacteristicDiscoveryFut = Ready<Result<Vec<Characteristic>>>;
321 type NotificationStream = UnboundedReceiver<Result<CharacteristicNotification>>;
322 type ReadFut<'a> = Ready<Result<(usize, bool)>>;
323 type WriteFut<'a> = Ready<Result<()>>;
324 type PeriodicAdvertising = FakePeriodicAdvertising;
325}
326
327impl ServerTypes for FakeTypes {
328 type Server = FakeServer;
329 type LocalService = FakeLocalService;
330 type LocalServiceFut = Ready<Result<FakeLocalService>>;
331 type ServiceEventStream = UnboundedReceiver<Result<server::ServiceEvent<FakeTypes>>>;
332 type ServiceWriteType = Vec<u8>;
333 type ReadResponder = FakeResponder;
334 type WriteResponder = FakeResponder;
335 type IndicateConfirmationStream = UnboundedReceiver<Result<server::ConfirmationEvent>>;
336}
337
338#[derive(Default)]
339struct FakePeriodicAdvertisingInner {
340 sync_registry: HashMap<PeerId, UnboundedSender<Result<SyncReport>>>,
341}
342
343#[derive(Clone, Default)]
344pub struct FakePeriodicAdvertising {
345 inner: Arc<Mutex<FakePeriodicAdvertisingInner>>,
346}
347
348impl FakePeriodicAdvertising {
349 pub fn new() -> Self {
350 Self::default()
351 }
352
353 pub fn get_sender(&self, peer_id: PeerId) -> Option<UnboundedSender<Result<SyncReport>>> {
354 self.inner.lock().sync_registry.get(&peer_id).cloned()
355 }
356}
357
358impl PeriodicAdvertising for FakePeriodicAdvertising {
359 type SyncFut = Ready<Result<Self::SyncStream>>;
360 type SyncStream = UnboundedReceiver<Result<SyncReport>>;
361
362 fn sync_to_advertising_reports(
363 &self,
364 peer_id: PeerId,
365 _advertising_sid: u8,
366 _config: crate::periodic_advertising::SyncConfiguration,
367 ) -> Self::SyncFut {
368 let (tx, rx) = unbounded();
369 self.inner.lock().sync_registry.insert(peer_id, tx);
370 ready(Ok(rx))
371 }
372}
373
374#[derive(Default)]
375pub struct FakeCentralInner {
376 clients: HashMap<PeerId, FakeClient>,
377 pub(crate) periodic_advertising: FakePeriodicAdvertising,
378}
379
380#[derive(Clone)]
381pub struct FakeCentral {
382 inner: Arc<Mutex<FakeCentralInner>>,
383}
384
385impl FakeCentral {
386 pub fn new() -> Self {
387 Self { inner: Arc::new(Mutex::new(FakeCentralInner::default())) }
388 }
389
390 pub fn add_client(&mut self, peer_id: PeerId, client: FakeClient) {
391 let _ = self.inner.lock().clients.insert(peer_id, client);
392 }
393}
394
395impl crate::Central<FakeTypes> for FakeCentral {
396 fn scan(&self, _filters: &[crate::central::ScanFilter]) -> ScannedResultStream {
397 ScannedResultStream::default()
398 }
399
400 fn connect(&self, peer_id: PeerId) -> <FakeTypes as GattTypes>::ConnectFuture {
401 let clients = &self.inner.lock().clients;
402 let res = match clients.get(&peer_id) {
403 Some(client) => Ok(client.clone()),
404 None => Err(Error::PeerDisconnected(peer_id)),
405 };
406 futures::future::ready(res)
407 }
408
409 fn periodic_advertising(&self) -> Result<<FakeTypes as GattTypes>::PeriodicAdvertising> {
410 Ok(self.inner.lock().periodic_advertising.clone())
411 }
412}
413
414#[derive(Debug)]
415pub enum FakeServerEvent {
416 ReadResponded {
417 service_id: server::ServiceId,
418 handle: Handle,
419 value: Result<Vec<u8>>,
420 },
421 WriteResponded {
422 service_id: server::ServiceId,
423 handle: Handle,
424 value: Result<()>,
425 },
426 Notified {
427 service_id: server::ServiceId,
428 handle: Handle,
429 value: Vec<u8>,
430 peers: Vec<PeerId>,
431 },
432 Indicated {
433 service_id: server::ServiceId,
434 handle: Handle,
435 value: Vec<u8>,
436 peers: Vec<PeerId>,
437 confirmations: UnboundedSender<Result<server::ConfirmationEvent>>,
438 },
439 Unpublished {
440 id: server::ServiceId,
441 },
442 Published {
443 id: server::ServiceId,
444 definition: ServiceDefinition,
445 },
446}
447
448#[derive(Debug)]
449struct FakeServerInner {
450 services: HashMap<server::ServiceId, ServiceDefinition>,
451 service_senders:
452 HashMap<server::ServiceId, UnboundedSender<Result<server::ServiceEvent<FakeTypes>>>>,
453 sender: UnboundedSender<FakeServerEvent>,
454 notification_peers: HashSet<PeerId>,
455 indication_peers: HashSet<PeerId>,
456}
457
458#[derive(Clone, Debug)]
459pub struct FakeServer {
460 inner: Arc<Mutex<FakeServerInner>>,
461}
462
463impl server::Server<FakeTypes> for FakeServer {
464 fn prepare(
465 &self,
466 service: server::ServiceDefinition,
467 ) -> <FakeTypes as ServerTypes>::LocalServiceFut {
468 let id = service.id();
469 self.inner.lock().services.insert(id, service);
470 futures::future::ready(Ok(FakeLocalService::new(id, self.inner.clone())))
471 }
472}
473
474impl FakeServer {
475 pub fn new() -> (Self, UnboundedReceiver<FakeServerEvent>) {
476 let (sender, receiver) = futures::channel::mpsc::unbounded();
477 (
478 Self {
479 inner: Arc::new(Mutex::new(FakeServerInner {
480 services: Default::default(),
481 service_senders: Default::default(),
482 sender,
483 notification_peers: HashSet::new(),
484 indication_peers: HashSet::new(),
485 })),
486 },
487 receiver,
488 )
489 }
490
491 pub fn service(&self, id: server::ServiceId) -> Option<ServiceDefinition> {
492 self.inner.lock().services.get(&id).cloned()
493 }
494
495 pub fn incoming_write(
496 &self,
497 peer_id: PeerId,
498 id: server::ServiceId,
499 handle: Handle,
500 offset: u32,
501 value: Vec<u8>,
502 ) {
503 let sender = self.inner.lock().sender.clone();
505 self.inner
506 .lock()
507 .service_senders
508 .get(&id)
509 .unwrap()
510 .unbounded_send(Ok(server::ServiceEvent::Write {
511 peer_id,
512 handle,
513 offset,
514 value,
515 responder: FakeResponder { sender, service_id: id, handle },
516 }))
517 .unwrap();
518 }
519
520 pub fn incoming_read(
521 &self,
522 peer_id: PeerId,
523 id: server::ServiceId,
524 handle: Handle,
525 offset: u32,
526 ) {
527 let sender = self.inner.lock().sender.clone();
529 self.inner
530 .lock()
531 .service_senders
532 .get(&id)
533 .unwrap()
534 .unbounded_send(Ok(server::ServiceEvent::Read {
535 peer_id,
536 handle,
537 offset,
538 responder: FakeResponder { sender, service_id: id, handle },
539 }))
540 .unwrap();
541 }
542
543 pub fn incoming_client_configuration(
544 &self,
545 peer_id: PeerId,
546 id: server::ServiceId,
547 handle: Handle,
548 notification_type: NotificationType,
549 ) {
550 let mut inner = self.inner.lock();
551 match notification_type {
552 NotificationType::Notify => {
553 inner.notification_peers.insert(peer_id);
554 }
555 NotificationType::Indicate => {
556 inner.indication_peers.insert(peer_id);
557 }
558 NotificationType::Disable => {
559 inner.notification_peers.remove(&peer_id);
560 inner.indication_peers.remove(&peer_id);
561 }
562 }
563 inner
564 .service_senders
565 .get(&id)
566 .unwrap()
567 .unbounded_send(Ok(server::ServiceEvent::ClientConfiguration {
568 peer_id,
569 handle,
570 notification_type,
571 }))
572 .unwrap();
573 }
574}
575
576pub struct FakeLocalService {
577 id: server::ServiceId,
578 inner: Arc<Mutex<FakeServerInner>>,
579}
580
581impl FakeLocalService {
582 fn new(id: server::ServiceId, inner: Arc<Mutex<FakeServerInner>>) -> Self {
583 Self { id, inner }
584 }
585}
586
587impl Drop for FakeLocalService {
588 fn drop(&mut self) {
589 self.inner.lock().services.remove(&self.id);
590 }
591}
592
593impl LocalService<FakeTypes> for FakeLocalService {
594 fn publish(&self) -> <FakeTypes as ServerTypes>::ServiceEventStream {
595 let (sender, receiver) = futures::channel::mpsc::unbounded();
596 let _ = self.inner.lock().service_senders.insert(self.id, sender);
597 let definition = self.inner.lock().services.get(&self.id).unwrap().clone();
598 self.inner
599 .lock()
600 .sender
601 .unbounded_send(FakeServerEvent::Published { id: self.id, definition })
602 .unwrap();
603 receiver
604 }
605
606 fn notify(&self, characteristic: &Handle, data: &[u8], peers: &[PeerId]) {
607 let inner = self.inner.lock();
608 let peers_to_notify: HashSet<_> = if peers.is_empty() {
609 inner.notification_peers.clone()
610 } else {
611 peers.iter().filter(|p| inner.notification_peers.contains(p)).cloned().collect()
612 };
613
614 if !peers_to_notify.is_empty() {
615 inner
616 .sender
617 .unbounded_send(FakeServerEvent::Notified {
618 service_id: self.id,
619 handle: *characteristic,
620 value: data.into(),
621 peers: peers_to_notify.into_iter().collect(),
622 })
623 .unwrap();
624 }
625 }
626
627 fn indicate(
628 &self,
629 characteristic: &Handle,
630 data: &[u8],
631 peers: &[PeerId],
632 ) -> <FakeTypes as ServerTypes>::IndicateConfirmationStream {
633 let (sender, receiver) = futures::channel::mpsc::unbounded();
634 let inner = self.inner.lock();
635 let peers_to_indicate: HashSet<_> = if peers.is_empty() {
636 inner.indication_peers.clone()
637 } else {
638 peers.iter().filter(|p| inner.indication_peers.contains(p)).cloned().collect()
639 };
640
641 if !peers_to_indicate.is_empty() {
642 inner
643 .sender
644 .unbounded_send(FakeServerEvent::Indicated {
645 service_id: self.id,
646 handle: *characteristic,
647 value: data.into(),
648 peers: peers_to_indicate.into_iter().collect(),
649 confirmations: sender,
650 })
651 .unwrap();
652 }
653 receiver
654 }
655}
656
657pub struct FakeResponder {
658 sender: UnboundedSender<FakeServerEvent>,
659 service_id: server::ServiceId,
660 handle: Handle,
661}
662
663impl ReadResponder for FakeResponder {
664 fn respond(self, value: &[u8]) {
665 self.sender
666 .unbounded_send(FakeServerEvent::ReadResponded {
667 service_id: self.service_id,
668 handle: self.handle,
669 value: Ok(value.into()),
670 })
671 .unwrap();
672 }
673
674 fn error(self, error: GattError) {
675 self.sender
676 .unbounded_send(FakeServerEvent::ReadResponded {
677 service_id: self.service_id,
678 handle: self.handle,
679 value: Err(Error::Gatt(error)),
680 })
681 .unwrap();
682 }
683}
684
685impl WriteResponder for FakeResponder {
686 fn acknowledge(self) {
687 self.sender
688 .unbounded_send(FakeServerEvent::WriteResponded {
689 service_id: self.service_id,
690 handle: self.handle,
691 value: Ok(()),
692 })
693 .unwrap();
694 }
695
696 fn error(self, error: GattError) {
697 self.sender
698 .unbounded_send(FakeServerEvent::WriteResponded {
699 service_id: self.service_id,
700 handle: self.handle,
701 value: Err(Error::Gatt(error)),
702 })
703 .unwrap();
704 }
705}