rnotifylib/message/
author.rs

1use std::fmt::{Display, Formatter};
2
3/// The hostname used when the hostname
4/// cannot be retrieved.
5const UNKNOWN_HOSTNAME: &str = "?";
6
7/// The author or creator of the message.
8///
9/// The base author will contain the hostname of the OS that sent to message.
10/// This helps identify which machine the message came from. If this is not available then '?' will
11/// be used.
12///
13/// A good author should allow the user to quickly and easily identify where the message
14/// originates from.
15/// To make a good author, think, could you quickly and easily stop the source of the messages just
16/// based on the author?
17///
18/// Filtering should not be performed based on an Author, rather you should filter instead
19/// based on [`Level`] and [`Component`]
20///
21/// [`Level`]: crate::message::Level
22/// [`Component`]: crate::message::component::Component
23#[derive(Debug, Clone, PartialEq)]
24pub struct Author {
25    parts: Vec<String>,
26}
27
28impl Author {
29    /// Parses an Author from the given string.
30    ///
31    /// ```rust
32    /// // A good Author for a message originating from the db_checker program
33    /// // which is invoked by user's crontab.
34    /// use rnotifylib::message::author::Author;
35    ///
36    /// let author = Author::parse("user/cron/db_checker".to_owned());
37    /// ```
38    pub fn parse(parts: String) -> Author {
39        let mut new = Self::base();
40        new.extend(parts);
41        new
42    }
43
44    /// Provides the base Author, of either the hostname.
45    /// If the hostname cannot be found, uses [`base_incognito`](Self::base_incognito)
46    pub fn base() -> Author {
47        let base = match hostname::get() {
48            Ok(hostname) => {
49                hostname.to_string_lossy().to_string()
50            }
51            Err(_) => {
52                return Self::base_incognito();
53            }
54        };
55
56        Author {
57            parts: vec![base],
58        }
59    }
60
61    /// Creates an Author with an unknown hostname.
62    /// You should use [`base`](Self::base) whenever possible, but if you do not want to expose
63    /// the hostname of the sender, you can use this method.
64    pub fn base_incognito() -> Author {
65        Author {
66            parts: vec![UNKNOWN_HOSTNAME.to_string()]
67        }
68    }
69
70    /// Parses an author, using an unknown hostname
71    /// You should use [`parse`](Self::parse) whenever possible, but if you do not want to expose
72    /// the hostname of the sender, you can use this method.
73    pub fn parse_incognito(s: String) -> Author {
74        let mut base = Self::base_incognito();
75        base.extend(s);
76        base
77    }
78
79    /// Adds more information to the author of this
80    /// ```rust
81    /// use rnotifylib::message::author::Author;
82    ///
83    /// // Normally you should use Author::base(), but we want predictable output for this test.
84    /// let mut author = Author::base_incognito();
85    /// author.extend("user".to_owned());
86    /// author.extend("cron".to_owned());
87    /// author.extend("db_checker".to_owned());
88    ///
89    /// assert_eq!(author.to_string(), "?/user/cron/db_checker");
90    pub fn extend(&mut self, parts: String) {
91        let vec: Vec<String> = parts.split("/").into_iter()
92            .filter(|s| !s.is_empty())
93            .map(|s| s.to_owned())
94            .collect();
95
96        self.parts.extend(vec);
97    }
98}
99
100impl Display for Author {
101    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102        write!(f, "{}", self.parts.join("/"))
103    }
104}