1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! # Events specification.

use anyhow::Result;
use tokio::sync::Mutex;

pub(crate) mod chatlist_events;
mod payload;

pub use self::payload::EventType;

/// Event channel.
#[derive(Debug, Clone)]
pub struct Events {
    /// Unused receiver to prevent the channel from closing.
    _receiver: async_broadcast::InactiveReceiver<Event>,

    /// Sender side of the event channel.
    sender: async_broadcast::Sender<Event>,
}

impl Default for Events {
    fn default() -> Self {
        Self::new()
    }
}

impl Events {
    /// Creates a new event channel.
    pub fn new() -> Self {
        let (mut sender, _receiver) = async_broadcast::broadcast(1_000);

        // We only keep this receiver around
        // to prevent the channel from closing.
        // Deactivating it to prevent it from consuming memory
        // holding events that are not going to be received.
        let _receiver = _receiver.deactivate();

        // Remove oldest event on overflow.
        sender.set_overflow(true);

        Self { _receiver, sender }
    }

    /// Emits an event into event channel.
    ///
    /// If the channel is full, deletes the oldest event first.
    pub fn emit(&self, event: Event) {
        self.sender.try_broadcast(event).ok();
    }

    /// Creates an event emitter.
    pub fn get_emitter(&self) -> EventEmitter {
        EventEmitter(Mutex::new(self.sender.new_receiver()))
    }
}

/// A receiver of events from a [`Context`].
///
/// See [`Context::get_event_emitter`] to create an instance.  If multiple instances are
/// created events emitted by the [`Context`] will only be delivered to one of the
/// `EventEmitter`s.
///
/// [`Context`]: crate::context::Context
/// [`Context::get_event_emitter`]: crate::context::Context::get_event_emitter
#[derive(Debug)]
pub struct EventEmitter(Mutex<async_broadcast::Receiver<Event>>);

impl EventEmitter {
    /// Async recv of an event. Return `None` if the `Sender` has been dropped.
    ///
    /// [`try_recv`]: Self::try_recv
    pub async fn recv(&self) -> Option<Event> {
        let mut lock = self.0.lock().await;
        match lock.recv().await {
            Err(async_broadcast::RecvError::Overflowed(n)) => Some(Event {
                id: 0,
                typ: EventType::EventChannelOverflow { n },
            }),
            Err(async_broadcast::RecvError::Closed) => None,
            Ok(event) => Some(event),
        }
    }

    /// Tries to receive an event without blocking.
    ///
    /// Returns error if no events are available for reception
    /// or if receiver mutex is locked by a concurrent call to [`recv`]
    /// or `try_recv`.
    ///
    /// [`recv`]: Self::recv
    pub fn try_recv(&self) -> Result<Event> {
        // Using `try_lock` instead of `lock`
        // to avoid blocking
        // in case there is a concurrent call to `recv`.
        let mut lock = self.0.try_lock()?;
        match lock.try_recv() {
            Err(async_broadcast::TryRecvError::Overflowed(n)) => {
                // Some events have been lost,
                // but the channel is not closed.
                Ok(Event {
                    id: 0,
                    typ: EventType::EventChannelOverflow { n },
                })
            }
            res @ (Err(async_broadcast::TryRecvError::Empty)
            | Err(async_broadcast::TryRecvError::Closed)
            | Ok(_)) => Ok(res?),
        }
    }
}

/// The event emitted by a [`Context`] from an [`EventEmitter`].
///
/// Events are documented on the C/FFI API in `deltachat.h` as `DC_EVENT_*` constants.  The
/// context emits them in relation to various operations happening, a lot of these are again
/// documented in `deltachat.h`.
///
/// [`Context`]: crate::context::Context
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Event {
    /// The ID of the [`Context`] which emitted this event.
    ///
    /// This allows using multiple [`Context`]s in a single process as they are identified
    /// by this ID.
    ///
    /// [`Context`]: crate::context::Context
    pub id: u32,
    /// The event payload.
    ///
    /// These are documented in `deltachat.h` as the `DC_EVENT_*` constants.
    pub typ: EventType,
}