rnotifylib/destination/
message_condition.rs

1use serde::{Serialize, Deserialize};
2use crate::message::component::Component;
3use crate::message::{Level, Message};
4
5/// A filter for a [`Message`]
6#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
7#[serde(deny_unknown_fields)]
8pub struct MessageCondition {
9    component: Option<Component>,
10    #[serde(default = "Level::min")]
11    min_level: Level,
12    #[serde(default = "Level::max")]
13    max_level: Level,
14}
15
16impl MessageCondition {
17    /// Creates a new MessageCondition, that requires ALL of the conditions to be met.
18    /// For each parameter, see the individual documentation
19    /// - [of_component](Self::of_component)
20    /// - [of_min](Self::of_min)
21    /// - [of_max](Self::of_max)
22    pub fn new(component: Option<Component>, min_level: Level, max_level: Level) -> Self {
23        Self {
24            component,
25            min_level,
26            max_level,
27        }
28    }
29
30    /// If present, then Messages must be a child of (or same as) this component as per [Component::is_child_of]
31    /// ```rust
32    /// use rnotifylib::destination::message_condition::MessageCondition;
33    /// use rnotifylib::message::builder::MessageBuilder;
34    /// use rnotifylib::message::component::Component;
35    /// use rnotifylib::message::Message;
36    ///
37    /// let condition_component = Component::from("database/backup");
38    /// let condition = MessageCondition::of_component(condition_component);
39    ///
40    /// fn make_message(component: &str) -> Message {
41    ///     let mut message_builder = MessageBuilder::new();
42    ///     message_builder.component(Component::from(component));
43    ///     message_builder.build()
44    /// }
45    ///
46    /// assert!(condition.matches(&make_message("database/backup")), "Should match itself");
47    ///
48    /// assert!(condition.matches(&make_message("database/backup/table1")), "Should match child");
49    /// assert!(condition.matches(&make_message("database/backup/table2")), "Should match child");
50    ///
51    /// assert!(!condition.matches(&make_message("database/uptime")), "Should not match - not to do with database backup");
52    /// assert!(!condition.matches(&make_message("fish_and_chip_shop/fries")), "Should not match - not to do with database");
53    /// ```
54    pub fn of_component(component: Component) -> Self {
55        Self {
56            component: Some(component),
57            ..Default::default()
58        }
59    }
60
61    /// Messages with a [`Level`] below this will not match this filter
62    /// ```rust
63    /// use rnotifylib::destination::message_condition::MessageCondition;
64    /// use rnotifylib::message::builder::MessageBuilder;
65    /// use rnotifylib::message::Level;
66    ///
67    /// let condition = MessageCondition::of_min(Level::Warn);
68    ///
69    /// let mut message_builder = MessageBuilder::new();
70    ///
71    /// message_builder.level(Level::Info);
72    /// let message = message_builder.build_clone();
73    /// assert!(!condition.matches(&message), "Info < Warn, so should not let through");
74    ///
75    /// message_builder.level(Level::Warn);
76    /// let message = message_builder.build_clone();
77    /// assert!(condition.matches(&message), "Warn >= Warn, so should be let through");
78    ///
79    /// message_builder.level(Level::Error);
80    /// let message = message_builder.build_clone();
81    /// assert!(condition.matches(&message), "Error >= Warn, so should let through")
82    ///
83    /// ```
84    pub fn of_min(min_level: Level) -> Self {
85        Self {
86            min_level,
87            ..Default::default()
88        }
89    }
90
91    /// Messages with a [`Level`] above this will not match this filter
92    /// ```rust
93    /// use rnotifylib::destination::message_condition::MessageCondition;
94    /// use rnotifylib::message::builder::MessageBuilder;
95    /// use rnotifylib::message::Level;
96    ///
97    /// let condition = MessageCondition::of_max(Level::Warn);
98    ///
99    /// let mut message_builder = MessageBuilder::new();
100    ///
101    /// message_builder.level(Level::Info);
102    /// let message = message_builder.build_clone();
103    /// assert!(condition.matches(&message), "Info <= Warn, so should let through");
104    ///
105    /// message_builder.level(Level::Warn);
106    /// let message = message_builder.build_clone();
107    /// assert!(condition.matches(&message), "Warn <= Warn, so should be let through");
108    ///
109    /// message_builder.level(Level::Error);
110    /// let message = message_builder.build_clone();
111    /// assert!(!condition.matches(&message), "Error > Warn,  so should not let through")
112    ///
113    /// ```
114    pub fn of_max(max_level: Level) -> Self {
115        Self {
116            max_level,
117            ..Default::default()
118        }
119    }
120
121    pub fn matches(&self, m: &Message) -> bool {
122        if let Some(c) = &self.component {
123            if m.get_component().is_none() || !m.get_component().as_ref().unwrap().is_child_of(c) {
124                return false;
125            }
126        }
127        &self.min_level <= m.get_level() && m.get_level() <= &self.max_level
128    }
129}
130
131impl Default for MessageCondition {
132    /// The default [MessageCondition] matches all messages.
133    fn default() -> Self {
134        Self {
135            component: None,
136            min_level: Level::min(),
137            max_level: Level::max(),
138        }
139    }
140}
141
142/// Conditionally notify a user / group, based on the given [MessageCondition].
143///
144/// Who this notifies is and the format of that is up to the specific implementation of
145/// the [`MessageDestination`](crate::destination::MessageDestination).
146#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
147pub struct MessageNotifyConditionConfigEntry<T> {
148    #[serde(flatten)]
149    message_condition: MessageCondition,
150    notify: T,
151}
152
153impl<T> MessageNotifyConditionConfigEntry<T> {
154    pub fn matches(&self, m: &Message) -> bool {
155        self.message_condition.matches(m)
156    }
157
158    pub fn get_notify(&self) -> &T {
159        &self.notify
160    }
161}