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}