fedimint_client/sm/
notifier.rs

1use fedimint_client_module::module::FinalClientIface;
2use fedimint_client_module::sm::{DynState, ModuleNotifier};
3use fedimint_core::core::ModuleInstanceId;
4use tracing::{debug, trace};
5
6/// State transition notifier owned by the modularized client used to inform
7/// modules of state transitions.
8///
9/// To not lose any state transitions that happen before a module subscribes to
10/// the operation the notifier loads all belonging past state transitions from
11/// the DB. State transitions may be reported multiple times and out of order.
12#[derive(Clone)]
13pub struct Notifier {
14    /// Broadcast channel used to send state transitions to all subscribers
15    broadcast: tokio::sync::broadcast::Sender<DynState>,
16}
17
18impl Notifier {
19    #[allow(clippy::new_without_default)]
20    pub fn new() -> Self {
21        let (sender, _receiver) = tokio::sync::broadcast::channel(10_000);
22        Self { broadcast: sender }
23    }
24
25    /// Notify all subscribers of a state transition
26    pub fn notify(&self, state: DynState) {
27        let queue_len = self.broadcast.len();
28        trace!(?state, %queue_len, "Sending notification about state transition");
29        // FIXME: use more robust notification mechanism
30        if let Err(e) = self.broadcast.send(state) {
31            debug!(
32                ?e,
33                %queue_len,
34                receivers=self.broadcast.receiver_count(),
35                "Could not send state transition notification, no active receivers"
36            );
37        }
38    }
39
40    /// Create a new notifier for a specific module instance that can only
41    /// subscribe to the instance's state transitions
42    pub fn module_notifier<S>(
43        &self,
44        module_instance: ModuleInstanceId,
45        client: FinalClientIface,
46    ) -> ModuleNotifier<S>
47    where
48        S: fedimint_client_module::sm::State,
49    {
50        ModuleNotifier::new(self.broadcast.clone(), module_instance, client)
51    }
52
53    /// Create a [`NotifierSender`] handle that lets the owner trigger
54    /// notifications without having to hold a full `Notifier`.
55    pub fn sender(&self) -> NotifierSender {
56        NotifierSender {
57            sender: self.broadcast.clone(),
58        }
59    }
60}
61
62/// Notifier send handle that can be shared to places where we don't need an
63/// entire [`Notifier`] but still need to trigger notifications. The main use
64/// case is triggering notifications when a DB transaction was committed
65/// successfully.
66pub struct NotifierSender {
67    sender: tokio::sync::broadcast::Sender<DynState>,
68}
69
70impl NotifierSender {
71    /// Notify all subscribers of a state transition
72    pub fn notify(&self, state: DynState) {
73        let _res = self.sender.send(state);
74    }
75}