deltachat/
events.rs

1//! # Events specification.
2
3use anyhow::Result;
4use tokio::sync::Mutex;
5
6pub(crate) mod chatlist_events;
7mod payload;
8
9pub use self::payload::EventType;
10
11/// Event channel.
12#[derive(Debug, Clone)]
13pub struct Events {
14    /// Unused receiver to prevent the channel from closing.
15    _receiver: async_broadcast::InactiveReceiver<Event>,
16
17    /// Sender side of the event channel.
18    sender: async_broadcast::Sender<Event>,
19}
20
21impl Default for Events {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl Events {
28    /// Creates a new event channel.
29    pub fn new() -> Self {
30        let (mut sender, _receiver) = async_broadcast::broadcast(1_000);
31
32        // We only keep this receiver around
33        // to prevent the channel from closing.
34        // Deactivating it to prevent it from consuming memory
35        // holding events that are not going to be received.
36        let _receiver = _receiver.deactivate();
37
38        // Remove oldest event on overflow.
39        sender.set_overflow(true);
40
41        Self { _receiver, sender }
42    }
43
44    /// Emits an event into event channel.
45    ///
46    /// If the channel is full, deletes the oldest event first.
47    pub fn emit(&self, event: Event) {
48        self.sender.try_broadcast(event).ok();
49    }
50
51    /// Creates an event emitter.
52    pub fn get_emitter(&self) -> EventEmitter {
53        EventEmitter(Mutex::new(self.sender.new_receiver()))
54    }
55}
56
57/// A receiver of events from a [`Context`].
58///
59/// See [`Context::get_event_emitter`] to create an instance.  If multiple instances are
60/// created events emitted by the [`Context`] will only be delivered to one of the
61/// `EventEmitter`s.
62///
63/// [`Context`]: crate::context::Context
64/// [`Context::get_event_emitter`]: crate::context::Context::get_event_emitter
65#[derive(Debug)]
66pub struct EventEmitter(Mutex<async_broadcast::Receiver<Event>>);
67
68impl EventEmitter {
69    /// Async recv of an event. Return `None` if the `Sender` has been dropped.
70    ///
71    /// [`try_recv`]: Self::try_recv
72    pub async fn recv(&self) -> Option<Event> {
73        let mut lock = self.0.lock().await;
74        match lock.recv().await {
75            Err(async_broadcast::RecvError::Overflowed(n)) => Some(Event {
76                id: 0,
77                typ: EventType::EventChannelOverflow { n },
78            }),
79            Err(async_broadcast::RecvError::Closed) => None,
80            Ok(event) => Some(event),
81        }
82    }
83
84    /// Tries to receive an event without blocking.
85    ///
86    /// Returns error if no events are available for reception
87    /// or if receiver mutex is locked by a concurrent call to [`recv`]
88    /// or `try_recv`.
89    ///
90    /// [`recv`]: Self::recv
91    pub fn try_recv(&self) -> Result<Event> {
92        // Using `try_lock` instead of `lock`
93        // to avoid blocking
94        // in case there is a concurrent call to `recv`.
95        let mut lock = self.0.try_lock()?;
96        match lock.try_recv() {
97            Err(async_broadcast::TryRecvError::Overflowed(n)) => {
98                // Some events have been lost,
99                // but the channel is not closed.
100                Ok(Event {
101                    id: 0,
102                    typ: EventType::EventChannelOverflow { n },
103                })
104            }
105            res @ (Err(async_broadcast::TryRecvError::Empty)
106            | Err(async_broadcast::TryRecvError::Closed)
107            | Ok(_)) => Ok(res?),
108        }
109    }
110}
111
112/// The event emitted by a [`Context`] from an [`EventEmitter`].
113///
114/// Events are documented on the C/FFI API in `deltachat.h` as `DC_EVENT_*` constants.  The
115/// context emits them in relation to various operations happening, a lot of these are again
116/// documented in `deltachat.h`.
117///
118/// [`Context`]: crate::context::Context
119#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct Event {
121    /// The ID of the [`Context`] which emitted this event.
122    ///
123    /// This allows using multiple [`Context`]s in a single process as they are identified
124    /// by this ID.
125    ///
126    /// [`Context`]: crate::context::Context
127    pub id: u32,
128    /// The event payload.
129    ///
130    /// These are documented in `deltachat.h` as the `DC_EVENT_*` constants.
131    pub typ: EventType,
132}