rnotifylib/destination/
routed_destination.rs

1use std::error::Error;
2use std::fmt::Debug;
3use serde::{Deserialize, Serialize};
4use crate::destination::MessageDestination;
5use crate::message::Message;
6use crate::message_router::RoutingInfo;
7
8/// A [Message] that also contains [RoutingInfo].
9pub trait RoutedDestination {
10    /// The id provides an identifier
11    /// for error reporting.
12    fn get_id(&self) -> &str;
13
14    /// The message destination that messages will
15    /// can be sent to.
16    fn get_destination(&self) -> &dyn MessageDestination;
17
18    /// The routing requirements of this destination.
19    fn get_routing_info(&self) -> &RoutingInfo;
20
21    fn send(&self, message: &Message) -> Result<(), Box<dyn Error>> {
22        self.get_destination().send(message)
23    }
24
25    fn is_root(&self) -> bool {
26        self.get_routing_info().get_routing_behaviour() == &MessageRoutingBehaviour::Root
27    }
28
29    fn get_routing_type(&self) -> &MessageRoutingBehaviour {
30        &self.get_routing_info().get_routing_behaviour()
31    }
32
33    fn should_receive(&self, m: &Message) -> bool {
34        self.get_routing_info().applies_to(m)
35    }
36}
37
38/// Handles whether messages are routed here / if they will be routed to other destinations.
39#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
40pub enum MessageRoutingBehaviour {
41    /// [`SelfError`] messages in addition to all messages will be sent here.
42    ///
43    /// It is recommended to have at least one Root destination, as this serves as a "log"
44    /// for all the notifications.
45    /// This is normally a [`FileDestination`] since that unlikely to fail.
46    ///
47    /// [`SelfError`]: crate::message::Level::SelfError
48    /// [`FileDestination`]: crate::destination::kinds::file::FileDestination
49    Root,
50    /// Messages will be sent here if they would not be sent elsewhere (excluding [Self::Root] destinations).
51    /// Useful if you want to route "unsorted" messages. A "lazy" destination - checks everything else first.
52    Drain,
53    /// The default option - Messages will be sent here under normal circumstances.
54    Additive
55}
56
57impl MessageRoutingBehaviour {
58    pub fn always_send_messages(&self) -> bool {
59        match &self {
60            MessageRoutingBehaviour::Root => true,
61            MessageRoutingBehaviour::Additive => true,
62
63            MessageRoutingBehaviour::Drain => false,
64        }
65    }
66
67    pub fn always_receives_errors(&self) -> bool {
68        match &self {
69            MessageRoutingBehaviour::Root => true,
70            MessageRoutingBehaviour::Drain => false,
71            MessageRoutingBehaviour::Additive => false,
72        }
73    }
74}
75
76impl Default for MessageRoutingBehaviour {
77    fn default() -> Self {
78        MessageRoutingBehaviour::Additive
79    }
80}
81
82// Implementations //
83
84#[derive(Debug)]
85pub struct RoutedDestinationBase {
86    id: String,
87    // Whether errors with sending notifications will be reported to this destination.
88    destination: Box<dyn MessageDestination>,
89    routing_info: RoutingInfo,
90}
91
92impl RoutedDestinationBase {
93    pub fn new(id: String, destination: Box<dyn MessageDestination>, routing_info: RoutingInfo) -> Self {
94        Self {
95            id,
96            destination,
97            routing_info,
98        }
99    }
100
101    pub fn create<M: MessageDestination + 'static>(id: String, destination: M, routing_info: RoutingInfo) -> Self {
102        Self {
103            id,
104            destination: Box::new(destination),
105            routing_info,
106        }
107    }
108}
109
110impl RoutedDestination for RoutedDestinationBase {
111    fn get_id(&self) -> &str {
112        &self.id
113    }
114
115    fn get_destination(&self) -> &dyn MessageDestination {
116        &*self.destination
117    }
118
119    fn get_routing_info(&self) -> &RoutingInfo {
120        &self.routing_info
121    }
122}
123
124
125#[cfg(test)]
126mod test {
127    use std::sync::mpsc;
128    use std::sync::mpsc::TryRecvError;
129    use super::*;
130    use crate::destination::kinds::rust_receiver::RustReceiverDestination;
131    use crate::message::{Level, MessageDetail};
132    use crate::message::author::Author;
133
134    #[test]
135    pub fn test_send_message() {
136        let (send, recv) = mpsc::channel();
137        let dest = RoutedDestinationBase::create("test".to_owned(), RustReceiverDestination::create(send), RoutingInfo::root());
138
139        let message = Message::new(Level::Info,
140                                   None, MessageDetail::Raw("hello".to_owned()),
141                                   None, Author::parse("test".to_owned()), 104892);
142
143
144        assert_eq!(recv.try_recv(), Err(TryRecvError::Empty), "Should be empty before we send a message");
145
146        dest.send(&message).expect("Should not fail to send message");
147
148        assert_eq!(recv.try_recv(), Ok(message));
149    }
150}