pass_it_on/
endpoints.rs

1//! Endpoints for the server
2
3use crate::notifications::{Key, ValidatedNotification};
4use crate::Error;
5use async_trait::async_trait;
6use dyn_clone::DynClone;
7use std::any::Any;
8use std::collections::{HashMap, HashSet};
9use std::fmt::Debug;
10use tokio::sync::{broadcast, watch};
11
12#[cfg(feature = "discord")]
13pub mod discord;
14#[cfg(feature = "email")]
15pub mod email;
16#[cfg(feature = "file")]
17pub mod file;
18#[cfg(feature = "matrix")]
19pub mod matrix;
20
21/// A data structure that can be deserialized and converted into an [`Endpoint`].
22#[typetag::deserialize(tag = "type")]
23pub trait EndpointConfig: Debug {
24    /// Convert this `EndpointConfig` into an [`Endpoint`].
25    fn to_endpoint(&self) -> Result<Box<dyn Endpoint + Send>, Error>;
26}
27
28/// A data structure that contains information and functions need the server needs to send messages to endpoint.
29#[async_trait]
30pub trait Endpoint: DynClone + Send + Debug {
31    /// Implements the server sending notifications to the `Endpoint`.
32    async fn notify(
33        &self,
34        endpoint_rx: broadcast::Receiver<ValidatedNotification>,
35        shutdown: watch::Receiver<bool>,
36    ) -> Result<(), Error>;
37
38    /// Generates a [`HashMap`] where the keys represent a sub-group of notifications.
39    ///
40    /// This is useful for endpoints like Matrix where multiple rooms can be setup, but all notifications going to the endpoint
41    /// do not go to all rooms.
42    /// For endpoints like File where this is not applicable all notifications can go under a single key.
43    fn generate_keys(&self, hash_key: &Key) -> HashMap<String, HashSet<Key>>;
44
45    /// Get [`Endpoint`] as [`Any`]
46    fn as_any(&self) -> &dyn Any;
47}
48
49dyn_clone::clone_trait_object!(Endpoint);
50
51#[derive(Clone)]
52pub(crate) struct EndpointChannel {
53    endpoint: Box<dyn Endpoint + Send>,
54    channel: broadcast::Sender<ValidatedNotification>,
55    keys: HashMap<String, HashSet<Key>>,
56}
57
58impl EndpointChannel {
59    pub fn from(
60        endpoint: Box<dyn Endpoint + Send>,
61        channel: broadcast::Sender<ValidatedNotification>,
62        keys: HashMap<String, HashSet<Key>>,
63    ) -> Self {
64        EndpointChannel { endpoint, channel, keys }
65    }
66
67    pub fn endpoint(&self) -> &Box<dyn Endpoint + Send> {
68        &self.endpoint
69    }
70
71    pub fn channel_receiver(&self) -> broadcast::Receiver<ValidatedNotification> {
72        self.channel.subscribe()
73    }
74
75    pub fn channel_sender(&self) -> broadcast::Sender<ValidatedNotification> {
76        self.channel.clone()
77    }
78
79    pub fn keys(&self) -> &HashMap<String, HashSet<Key>> {
80        &self.keys
81    }
82}
83
84pub(crate) async fn setup_endpoints(
85    endpoints: Vec<EndpointChannel>,
86    shutdown: watch::Receiver<bool>,
87) -> Result<(), Error> {
88    for channel in endpoints {
89        channel.endpoint().notify(channel.channel_receiver(), shutdown.clone()).await?
90    }
91    Ok(())
92}