1use dbus::nonblock::Proxy;
8use dbus_crossroads::{Crossroads, IfaceBuilder, IfaceToken};
9use futures::{Stream, StreamExt};
10use std::{
11 fmt,
12 pin::Pin,
13 sync::Arc,
14 task::{Context, Poll},
15 time::Duration,
16};
17use strum::{Display, EnumString};
18use tokio::sync::{mpsc, oneshot, Mutex};
19use tokio_stream::wrappers::ReceiverStream;
20use uuid::Uuid;
21
22use crate::{
23 method_call, Address, DbusResult, Device, Error, ErrorKind, Result, SessionInner, SERVICE_NAME, TIMEOUT,
24};
25
26pub(crate) const INTERFACE: &str = "org.bluez.AdvertisementMonitor1";
27pub(crate) const MANAGER_INTERFACE: &str = "org.bluez.AdvertisementMonitorManager1";
28pub(crate) const MANAGER_PATH: &str = "/org/bluez";
29pub(crate) const MONITOR_PREFIX: &str = publish_path!("monitor");
30
31#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Display, EnumString)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34#[non_exhaustive]
35pub enum Type {
36 #[strum(serialize = "or_patterns")]
38 OrPatterns,
39}
40
41impl Default for Type {
42 fn default() -> Self {
43 Self::OrPatterns
44 }
45}
46
47pub mod data_type {
52 pub const FLAGS: u8 = 0x01;
54
55 pub const INCOMPLETE_LIST_16_BIT_SERVICE_CLASS_UUIDS: u8 = 0x02;
58
59 pub const COMPLETE_LIST_16_BIT_SERVICE_CLASS_UUIDS: u8 = 0x03;
62
63 pub const INCOMPLETE_LIST_32_BIT_SERVICE_CLASS_UUIDS: u8 = 0x04;
66
67 pub const COMPLETE_LIST_32_BIT_SERVICE_CLASS_UUIDS: u8 = 0x05;
70
71 pub const INCOMPLETE_LIST_128_BIT_SERVICE_CLASS_UUIDS: u8 = 0x06;
74
75 pub const COMPLETE_LIST_128_BIT_SERVICE_CLASS_UUIDS: u8 = 0x07;
78
79 pub const SHORTENED_LOCAL_NAME: u8 = 0x08;
81
82 pub const COMPLETE_LOCAL_NAME: u8 = 0x09;
84
85 pub const TX_POWER_LEVEL: u8 = 0x0A;
87
88 pub const MANUFACTURER_SPECIFIC_DATA: u8 = 0xFF;
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
94#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
95pub struct Pattern {
96 pub data_type: u8,
100 pub start_position: u8,
104 pub content: Vec<u8>,
108}
109
110impl Pattern {
111 pub fn new(data_type: u8, start_position: u8, content: &[u8]) -> Self {
115 Self { data_type, start_position, content: content.to_vec() }
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
122#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
123pub enum RssiSamplingPeriod {
124 All,
127 First,
132 Period(Duration),
137}
138
139impl RssiSamplingPeriod {
140 fn to_value(self) -> u16 {
141 match self {
142 Self::All => 0,
143 Self::First => 255,
144 Self::Period(period) => (period.as_millis() / 100).clamp(1, 254) as u16,
145 }
146 }
147}
148
149#[derive(Default)]
155pub struct Monitor {
156 pub monitor_type: Type,
158
159 pub rssi_low_threshold: Option<i16>,
164
165 pub rssi_high_threshold: Option<i16>,
170
171 pub rssi_low_timeout: Option<Duration>,
180
181 pub rssi_high_timeout: Option<Duration>,
190
191 pub rssi_sampling_period: Option<RssiSamplingPeriod>,
194
195 pub patterns: Option<Vec<Pattern>>,
200
201 #[doc(hidden)]
202 pub _non_exhaustive: (),
203}
204
205#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
207#[non_exhaustive]
208pub struct DeviceId {
209 pub adapter: String,
211 pub device: Address,
213}
214
215#[derive(Debug, Clone, PartialEq, Eq)]
217#[non_exhaustive]
218pub enum MonitorEvent {
219 DeviceFound(DeviceId),
226
227 DeviceLost(DeviceId),
233}
234
235pub(crate) struct RegisteredMonitor {
236 am: Monitor,
237 activate_tx: mpsc::Sender<()>,
238 release_tx: mpsc::Sender<()>,
239 event_tx: Mutex<Option<mpsc::Sender<MonitorEvent>>>,
240}
241
242impl RegisteredMonitor {
243 fn parse_device_path(device: &dbus::Path<'static>) -> DbusResult<(String, Address)> {
244 match Device::parse_dbus_path(device) {
245 Some((adapter, addr)) => Ok((adapter.to_string(), addr)),
246 None => {
247 log::error!("Cannot parse device path {}", &device);
248 Err(dbus::MethodErr::invalid_arg("cannot parse device path"))
249 }
250 }
251 }
252
253 pub(crate) fn register_interface(cr: &mut Crossroads) -> IfaceToken<Arc<RegisteredMonitor>> {
254 cr.register(INTERFACE, |ib: &mut IfaceBuilder<Arc<RegisteredMonitor>>| {
255 ib.method_with_cr_async("Release", (), (), |ctx, cr, ()| {
256 method_call(ctx, cr, |reg: Arc<RegisteredMonitor>| async move {
257 *reg.event_tx.lock().await = None;
258 let _ = reg.release_tx.send(()).await;
259 Ok(())
260 })
261 });
262
263 ib.method_with_cr_async("Activate", (), (), |ctx, cr, ()| {
264 method_call(ctx, cr, |reg: Arc<RegisteredMonitor>| async move {
265 let _ = reg.activate_tx.send(()).await;
266 Ok(())
267 })
268 });
269
270 ib.method_with_cr_async(
271 "DeviceFound",
272 ("device",),
273 (),
274 |ctx, cr, (addr,): (dbus::Path<'static>,)| {
275 method_call(ctx, cr, |reg: Arc<RegisteredMonitor>| async move {
276 let (adapter, device) = Self::parse_device_path(&addr)?;
277 if let Some(event_tx) = reg.event_tx.lock().await.as_ref() {
278 let _ = event_tx.send(MonitorEvent::DeviceFound(DeviceId { adapter, device })).await;
279 }
280 Ok(())
281 })
282 },
283 );
284
285 ib.method_with_cr_async("DeviceLost", ("device",), (), |ctx, cr, (addr,): (dbus::Path<'static>,)| {
286 method_call(ctx, cr, move |reg: Arc<RegisteredMonitor>| async move {
287 let (adapter, device) = Self::parse_device_path(&addr)?;
288 if let Some(event_tx) = reg.event_tx.lock().await.as_ref() {
289 let _ = event_tx.send(MonitorEvent::DeviceLost(DeviceId { adapter, device })).await;
290 }
291 Ok(())
292 })
293 });
294
295 cr_property!(ib, "Type", r => {
296 Some(r.am.monitor_type.to_string())
297 });
298
299 cr_property!(ib, "RSSILowThreshold", r => {
300 r.am.rssi_low_threshold
301 });
302
303 cr_property!(ib, "RSSIHighThreshold", r => {
304 r.am.rssi_high_threshold
305 });
306
307 cr_property!(ib, "RSSILowTimeout", r => {
308 r.am.rssi_low_timeout.map(|t| t.as_secs().clamp(1, 300) as u16)
309 });
310
311 cr_property!(ib, "RSSIHighTimeout", r => {
312 r.am.rssi_high_timeout.map(|t| t.as_secs().clamp(1, 300) as u16)
313 });
314
315 cr_property!(ib, "RSSISamplingPeriod", r => {
316 r.am.rssi_sampling_period.map(|v| v.to_value())
317 });
318
319 cr_property!(ib, "Patterns", r => {
320 r.am.patterns.as_ref().map(|patterns: &Vec<Pattern>| {
321 patterns
322 .iter()
323 .map(|p| (p.start_position, p.data_type, p.content.clone()))
324 .collect::<Vec<_>>()
325 })
326 });
327 })
328 }
329}
330
331#[must_use = "the MonitorHandle must be held for the monitor to be active and its events must be consumed regularly"]
341pub struct MonitorHandle {
342 name: dbus::Path<'static>,
343 event_rx: ReceiverStream<MonitorEvent>,
344 _drop_tx: oneshot::Sender<()>,
345}
346
347impl fmt::Debug for MonitorHandle {
348 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
349 write!(f, "MonitorHandle {{ {} }}", &self.name)
350 }
351}
352
353impl Stream for MonitorHandle {
354 type Item = MonitorEvent;
355
356 fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
357 Pin::into_inner(self).event_rx.poll_next_unpin(cx)
358 }
359}
360
361impl Drop for MonitorHandle {
362 fn drop(&mut self) {
363 }
365}
366
367pub struct MonitorManager {
377 inner: Arc<SessionInner>,
378 root: dbus::Path<'static>,
379 _drop_tx: oneshot::Sender<()>,
380}
381
382impl fmt::Debug for MonitorManager {
383 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
384 f.debug_struct("MonitorManager").finish()
385 }
386}
387
388impl MonitorManager {
389 pub(crate) async fn new(inner: Arc<SessionInner>, adapter_name: &str) -> Result<Self> {
390 let manager_path = dbus::Path::new(format!("{}/{}", MANAGER_PATH, adapter_name)).unwrap();
391 let root = dbus::Path::new(format!("{}/{}", MONITOR_PREFIX, Uuid::new_v4().as_simple())).unwrap();
392
393 log::trace!("Publishing advertisement monitor root at {}", &root);
394
395 {
396 let mut cr = inner.crossroads.lock().await;
397 let object_manager_token = cr.object_manager();
398 let introspectable_token = cr.introspectable();
399 let properties_token = cr.properties();
400 cr.insert(root.clone(), [&object_manager_token, &introspectable_token, &properties_token], ());
401 }
402
403 log::trace!("Registering advertisement monitor root at {}", &root);
404 let proxy = Proxy::new(SERVICE_NAME, manager_path, TIMEOUT, inner.connection.clone());
405 let () = proxy.method_call(MANAGER_INTERFACE, "RegisterMonitor", (root.clone(),)).await?;
406
407 let (_drop_tx, drop_rx) = oneshot::channel();
408 let unreg_root = root.clone();
409 let unreg_inner = inner.clone();
410 tokio::spawn(async move {
411 let _ = drop_rx.await;
412
413 log::trace!("Unregistering advertisement monitor root at {}", &unreg_root);
414 let _: std::result::Result<(), dbus::Error> =
415 proxy.method_call(MANAGER_INTERFACE, "UnregisterMonitor", (unreg_root.clone(),)).await;
416
417 log::trace!("Unpublishing advertisement monitor root at {}", &unreg_root);
418 let mut cr = unreg_inner.crossroads.lock().await;
419 cr.remove::<()>(&unreg_root);
420 });
421
422 Ok(Self { inner, root, _drop_tx })
423 }
424
425 pub async fn register(&self, advertisement_monitor: Monitor) -> Result<MonitorHandle> {
429 let name = dbus::Path::new(format!("{}/{}", &self.root, Uuid::new_v4().as_simple())).unwrap();
430
431 log::trace!("Publishing advertisement monitor target at {}", &name);
432
433 let (activate_tx, mut activate_rx) = mpsc::channel(1);
434 let (release_tx, mut release_rx) = mpsc::channel(1);
435 let (event_tx, event_rx) = mpsc::channel(1024);
436 let (_drop_tx, drop_rx) = oneshot::channel();
437
438 let reg = RegisteredMonitor {
439 am: advertisement_monitor,
440 activate_tx,
441 release_tx,
442 event_tx: Mutex::new(Some(event_tx)),
443 };
444
445 {
446 let mut cr = self.inner.crossroads.lock().await;
447 cr.insert(name.clone(), [&self.inner.monitor_token], Arc::new(reg));
448 }
449
450 let inner = self.inner.clone();
451 let unreg_name = name.clone();
452 tokio::spawn(async move {
453 let _ = drop_rx.await;
454
455 log::trace!("Unpublishing advertisement monitor target at {}", &unreg_name);
456 let mut cr = inner.crossroads.lock().await;
457 cr.remove::<Arc<RegisteredMonitor>>(&unreg_name);
458 });
459
460 tokio::select! {
461 biased;
462 _ = release_rx.recv() => return Err(Error::new(ErrorKind::AdvertisementMonitorRejected)),
463 res = activate_rx.recv() => {
464 if res.is_none() {
465 return Err(Error::new(ErrorKind::AdvertisementMonitorRejected))
466 }
467 },
468 }
469
470 Ok(MonitorHandle { name, event_rx: event_rx.into(), _drop_tx })
471 }
472}
473
474impl Drop for MonitorManager {
475 fn drop(&mut self) {
476 }
478}