dittolive_ditto/presence/
observer.rs

1use_prelude!();
2
3use std::hash::Hash;
4
5use ffi_sdk::{FfiDynPresenceCallback, FfiPresenceObserver};
6use uuid::Uuid;
7
8use crate::error::Result;
9
10trait_alias! {
11    pub trait PresenceCallback = FnMut(&PresenceGraph) + Send + Sync + 'static
12}
13
14/// Use [`ditto.presence().register_observer(...)`] to create a new `PresenceObserver`.
15///
16/// # Example
17///
18/// ```
19/// use dittolive_ditto::Ditto;
20/// # fn main() -> anyhow::Result<()> {
21/// # let (_root, ditto) = dittolive_ditto::doctest_helpers::doctest_ditto();
22///
23/// // To register a new presence observer
24/// let observer = ditto.presence().register_observer(|graph| {
25///     println!("Graph updated: {:?}", graph);
26/// })?;
27///
28/// // Later, to cancel the observer
29/// observer.cancel();
30/// # Ok(())
31/// # }
32/// ```
33///
34/// [`ditto.presence().register_observer(...)`]: crate::presence::Presence::register_observer
35pub struct PresenceObserver {
36    pub(crate) handle: repr_c::Box<FfiPresenceObserver>,
37}
38
39impl PresenceObserver {
40    /// Create a new `PresenceObserver` with the given callback to receive presence updates.
41    pub(crate) fn new<F>(ditto: &ffi_sdk::BoxedDitto, mut observer: F) -> Result<PresenceObserver>
42    where
43        F: PresenceCallback,
44    {
45        let ffi_callback: repr_c::Box<FfiDynPresenceCallback> = {
46            fn make_callback<F>(f: F) -> repr_c::Box<FfiDynPresenceCallback>
47            where
48                F: 'static + Send + FnMut(c_slice::Box<u8>),
49            {
50                Box::new(f).into()
51            }
52
53            make_callback(move |graph: c_slice::Box<u8>| {
54                let graph =
55                    serde_json::from_slice(&graph).expect("should deserialize presence graph");
56                observer(&graph);
57            })
58        };
59
60        let handle = ffi_sdk::dittoffi_presence_register_observer_throws(ditto, ffi_callback)
61            .into_rust_result()?;
62        Ok(Self { handle })
63    }
64
65    /// Cancels this [`PresenceObserver`]. The registered callback will no longer be called.
66    pub fn cancel(&self) {
67        ffi_sdk::dittoffi_presence_observer_cancel(&self.handle);
68    }
69
70    /// Returns whether this [`PresenceObserver`] has been cancelled.
71    pub fn is_cancelled(&self) -> bool {
72        ffi_sdk::dittoffi_presence_observer_is_cancelled(&self.handle)
73    }
74
75    /// Returns the unique identifier for this [`PresenceObserver`].
76    fn id(&self) -> Uuid {
77        let buffer = ffi_sdk::dittoffi_presence_observer_id(&self.handle);
78        Uuid::from_slice(buffer.as_slice()).expect("bug: expected valid UUID")
79    }
80}
81
82impl Eq for PresenceObserver {}
83impl PartialEq for PresenceObserver {
84    fn eq(&self, other: &Self) -> bool {
85        self.id() == other.id()
86    }
87}
88
89impl Hash for PresenceObserver {
90    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
91        self.id().hash(state);
92    }
93}