media_remote/high_level/subscription.rs
1use std::{
2 collections::HashMap,
3 sync::{
4 atomic::{AtomicU64, Ordering},
5 Arc, Mutex, RwLockReadGuard,
6 },
7};
8
9use crate::NowPlayingInfo;
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub struct ListenerToken(u64);
13
14pub trait Subscription {
15 fn get_info(&self) -> RwLockReadGuard<'_, Option<NowPlayingInfo>>;
16
17 fn get_token_counter(&self) -> Arc<AtomicU64>;
18
19 fn get_listeners(
20 &self,
21 ) -> Arc<
22 Mutex<
23 HashMap<
24 ListenerToken,
25 Box<dyn Fn(RwLockReadGuard<'_, Option<NowPlayingInfo>>) + Send + Sync>,
26 >,
27 >,
28 >;
29
30 /// Subscribes a listener to receive updates when the "Now Playing" information changes.
31 ///
32 /// # Arguments
33 /// - `listener`: A function or closure that accepts a `RwLockReadGuard<'_, Option<NowPlayingInfo>>`.
34 /// The function will be invoked with the current "Now Playing" info whenever the data is updated.
35 ///
36 /// # Returns
37 /// - `ListenerToken`: A token representing the listener, which can later be used to unsubscribe.
38 ///
39 /// # Example
40 /// ```rust
41 /// use media_remote::prelude::*;
42 ///
43 /// let now_playing: NowPlaying = NowPlaying::new();
44 ///
45 /// now_playing.subscribe(|guard| {
46 /// let info = guard.as_ref();
47 /// if let Some(info) = info {
48 /// println!("Currently playing: {:?}", info.title);
49 /// }
50 /// });
51 /// ```
52 fn subscribe<F: Fn(RwLockReadGuard<'_, Option<NowPlayingInfo>>) + Send + Sync + 'static>(
53 &self,
54 listener: F,
55 ) -> ListenerToken {
56 listener(self.get_info());
57
58 let token = ListenerToken(self.get_token_counter().fetch_add(1, Ordering::Relaxed));
59
60 self.get_listeners()
61 .lock()
62 .unwrap()
63 .insert(token.clone(), Box::new(listener));
64
65 token
66 }
67
68 /// Unsubscribes a previously registered listener using the provided `ListenerToken`.
69 ///
70 ///
71 /// # Arguments
72 /// - `token`: The `ListenerToken` returned when the listener was subscribed. It is used to identify
73 /// and remove the listener.
74 ///
75 /// # Example
76 /// ```rust
77 /// use media_remote::prelude::*;
78 ///
79 /// let now_playing: NowPlaying = NowPlaying::new();
80 ///
81 /// let token = now_playing.subscribe(|guard| {
82 /// let info = guard.as_ref();
83 /// if let Some(info) = info {
84 /// println!("Currently playing: {:?}", info.title);
85 /// }
86 /// });
87 ///
88 /// now_playing.unsubscribe(token);
89 /// ```
90 fn unsubscribe(&self, token: ListenerToken) {
91 let binding = self.get_listeners();
92 let mut listeners = binding.lock().unwrap();
93 listeners.remove(&token);
94 }
95}