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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
use serde::{Serialize, Deserialize};
use crate::message::component::Component;
use crate::message::{Level, Message};
/// A filter for a [`Message`]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct MessageCondition {
component: Option<Component>,
#[serde(default = "Level::min")]
min_level: Level,
#[serde(default = "Level::max")]
max_level: Level,
}
impl MessageCondition {
/// Creates a new MessageCondition, that requires ALL of the conditions to be met.
/// For each parameter, see the individual documentation
/// - [of_component](Self::of_component)
/// - [of_min](Self::of_min)
/// - [of_max](Self::of_max)
pub fn new(component: Option<Component>, min_level: Level, max_level: Level) -> Self {
Self {
component,
min_level,
max_level,
}
}
/// If present, then Messages must be a child of (or same as) this component as per [Component::is_child_of]
/// ```rust
/// use rnotifylib::destination::message_condition::MessageCondition;
/// use rnotifylib::message::builder::MessageBuilder;
/// use rnotifylib::message::component::Component;
/// use rnotifylib::message::Message;
///
/// let condition_component = Component::from("database/backup");
/// let condition = MessageCondition::of_component(condition_component);
///
/// fn make_message(component: &str) -> Message {
/// let mut message_builder = MessageBuilder::new();
/// message_builder.component(Component::from(component));
/// message_builder.build()
/// }
///
/// assert!(condition.matches(&make_message("database/backup")), "Should match itself");
///
/// assert!(condition.matches(&make_message("database/backup/table1")), "Should match child");
/// assert!(condition.matches(&make_message("database/backup/table2")), "Should match child");
///
/// assert!(!condition.matches(&make_message("database/uptime")), "Should not match - not to do with database backup");
/// assert!(!condition.matches(&make_message("fish_and_chip_shop/fries")), "Should not match - not to do with database");
/// ```
pub fn of_component(component: Component) -> Self {
Self {
component: Some(component),
..Default::default()
}
}
/// Messages with a [`Level`] below this will not match this filter
/// ```rust
/// use rnotifylib::destination::message_condition::MessageCondition;
/// use rnotifylib::message::builder::MessageBuilder;
/// use rnotifylib::message::Level;
///
/// let condition = MessageCondition::of_min(Level::Warn);
///
/// let mut message_builder = MessageBuilder::new();
///
/// message_builder.level(Level::Info);
/// let message = message_builder.build_clone();
/// assert!(!condition.matches(&message), "Info < Warn, so should not let through");
///
/// message_builder.level(Level::Warn);
/// let message = message_builder.build_clone();
/// assert!(condition.matches(&message), "Warn >= Warn, so should be let through");
///
/// message_builder.level(Level::Error);
/// let message = message_builder.build_clone();
/// assert!(condition.matches(&message), "Error >= Warn, so should let through")
///
/// ```
pub fn of_min(min_level: Level) -> Self {
Self {
min_level,
..Default::default()
}
}
/// Messages with a [`Level`] above this will not match this filter
/// ```rust
/// use rnotifylib::destination::message_condition::MessageCondition;
/// use rnotifylib::message::builder::MessageBuilder;
/// use rnotifylib::message::Level;
///
/// let condition = MessageCondition::of_max(Level::Warn);
///
/// let mut message_builder = MessageBuilder::new();
///
/// message_builder.level(Level::Info);
/// let message = message_builder.build_clone();
/// assert!(condition.matches(&message), "Info <= Warn, so should let through");
///
/// message_builder.level(Level::Warn);
/// let message = message_builder.build_clone();
/// assert!(condition.matches(&message), "Warn <= Warn, so should be let through");
///
/// message_builder.level(Level::Error);
/// let message = message_builder.build_clone();
/// assert!(!condition.matches(&message), "Error > Warn, so should not let through")
///
/// ```
pub fn of_max(max_level: Level) -> Self {
Self {
max_level,
..Default::default()
}
}
pub fn matches(&self, m: &Message) -> bool {
if let Some(c) = &self.component {
if m.get_component().is_none() || !m.get_component().as_ref().unwrap().is_child_of(c) {
return false;
}
}
&self.min_level <= m.get_level() && m.get_level() <= &self.max_level
}
}
impl Default for MessageCondition {
/// The default [MessageCondition] matches all messages.
fn default() -> Self {
Self {
component: None,
min_level: Level::min(),
max_level: Level::max(),
}
}
}
/// Conditionally notify a user / group, based on the given [MessageCondition].
///
/// Who this notifies is and the format of that is up to the specific implementation of
/// the [`MessageDestination`](crate::destination::MessageDestination).
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct MessageNotifyConditionConfigEntry<T> {
#[serde(flatten)]
message_condition: MessageCondition,
notify: T,
}
impl<T> MessageNotifyConditionConfigEntry<T> {
pub fn matches(&self, m: &Message) -> bool {
self.message_condition.matches(m)
}
pub fn get_notify(&self) -> &T {
&self.notify
}
}