rnotifylib/message/mod.rs
1use std::cmp::Ordering;
2use std::fmt::Debug;
3use message::formatted_detail::FormattedMessageDetail;
4use serde::{Serialize, Deserialize};
5use crate::message;
6use crate::message::author::Author;
7use crate::message::component::Component;
8
9pub mod formatted_detail;
10pub mod author;
11pub mod component;
12pub mod builder;
13pub mod detail_builder;
14
15/// A Message represents a [`MessageDestination`] independent way to send a message to a platform.
16/// **However** - not every destination will support every type of formatting, or may have length / size
17/// restrictions - so be aware of this. Destinations should do their best to receive the message, even if they
18/// have to ignore formatting to do so.
19///
20/// To construct a Message, consider using [`MessageBuilder`] or [`MessageDetailBuilder`] to make
21/// your life easier.
22///
23/// # Parts of a Message #
24/// - [Level] - Severity of message
25/// - Title - Optional, short snappy summary of what the message is about
26/// - [MessageDetail] - Structured body text supporting formatting
27/// - [Component] - Optional, indicating what the message is about, e.g a program or server.
28/// - [Author] - Who created the message
29/// - Timestamp - The unix timestamp in milliseconds, showing when the message was sent.
30///
31/// [`MessageDestination`]: crate::destination::MessageDestination
32/// [`MessageBuilder`]: builder::MessageBuilder
33/// [`MessageDetailBuilder`]: detail_builder::MessageDetailBuilder
34#[derive(Debug, Clone, PartialEq)]
35pub struct Message {
36 level: Level,
37 title: Option<String>,
38 message_detail: MessageDetail,
39 component: Option<Component>,
40 author: Author,
41 unix_timestamp_millis: i64,
42}
43
44impl Message {
45 pub fn new(level: Level, title: Option<String>,
46 message_detail: MessageDetail, component: Option<Component>,
47 author: Author, unix_timestamp_millis: i64,
48 ) -> Self {
49 Self {
50 level,
51 title,
52 message_detail,
53 component,
54 author,
55 unix_timestamp_millis
56 }
57 }
58
59 pub fn get_level(&self) -> &Level {
60 &self.level
61 }
62
63 pub fn get_title(&self) -> &Option<String> {
64 &self.title
65 }
66
67 pub fn get_message_detail(&self) -> &MessageDetail {
68 &self.message_detail
69 }
70
71 pub fn get_unix_timestamp_millis(&self) -> i64 {
72 self.unix_timestamp_millis
73 }
74
75 pub fn get_author(&self) -> &Author {
76 &self.author
77 }
78
79 pub fn get_component(&self) -> &Option<Component> {
80 &self.component
81 }
82}
83
84#[derive(Debug, Clone, PartialEq)]
85pub enum MessageDetail {
86 Raw(String),
87 Formatted(FormattedMessageDetail),
88}
89
90impl MessageDetail {
91 pub fn raw(&self) -> &str {
92 match &self {
93 MessageDetail::Raw(raw) => raw,
94 MessageDetail::Formatted(formatted) => formatted.raw()
95 }
96 }
97
98 pub fn has_formatting(&self) -> bool {
99 matches!(&self, MessageDetail::Formatted(_))
100 }
101}
102
103impl Default for MessageDetail {
104 fn default() -> Self {
105 Self::Raw(String::new())
106 }
107}
108
109/// The level / severity of the [Message]. This can be thought of as the log level.
110/// This is used in conjunction to [Component] to indicate how a message should be
111/// routed.
112#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
113#[cfg_attr(feature = "binary", derive(clap::ArgEnum))]
114pub enum Level {
115 /// Indicates an informational message when everything is working properly.
116 /// # Examples #
117 /// - A job has completed successfully, e.g a backup
118 /// - A daily status update to confirm that everything is running correctly.
119 Info,
120 /// Used when something unexpected occurs that could be the source of an error,
121 /// but requires the user to check whether it is actually an issue.
122 ///
123 /// # Examples #
124 /// - A job took longer than normal
125 /// - A job failed that fails fairly regularly, but will presumably sort itself out soon.
126 Warn,
127 /// Indicates a failure has occurred.
128 ///
129 /// # Examples #
130 /// - A program crashed / had a non-zero exit code
131 /// - A monitoring program detected that another program has not completed its job
132 /// - Possibly indicating the program is not running
133 /// - Or the program is malfunctioning
134 /// - A program restarted in attempt to recover itself, but is expected to recover safely
135 Error,
136 /// Indicates a failure in the notifications own configuration / workings.
137 ///
138 /// # Examples #
139 /// - Sent by [`MessageRouter`] to [`Root`] level [`MessageDestination`]s when a message
140 /// cannot be sent to one or more destinations (e.g. network failure, invalid tokens)
141 ///
142 /// [`Root`]: crate::destination::routed_destination::MessageRoutingBehaviour::Root
143 /// [`MessageDestination`]: crate::destination::MessageDestination
144 /// [`MessageRouter`]: crate::message_router::MessageRouter
145 SelfError,
146}
147
148impl Default for Level {
149 fn default() -> Self {
150 Self::Info
151 }
152}
153
154impl Level {
155 pub(crate) fn get_priority(&self) -> u32 {
156 match &self {
157 Self::Info => 1,
158 Self::Warn => 3,
159 Self::Error => 4,
160 Self::SelfError => 5,
161 }
162 }
163
164 /// Gets the least severe [Level]
165 pub fn min() -> Level {
166 Level::Info
167 }
168
169 /// Gets the most severe [Level]
170 pub fn max() -> Level {
171 Level::SelfError
172 }
173}
174
175impl PartialOrd<Self> for Level {
176 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
177 Some(self.cmp(other))
178 }
179}
180
181impl Ord for Level {
182 fn cmp(&self, other: &Self) -> Ordering {
183 self.get_priority().cmp(&other.get_priority())
184 }
185}