mymq/
config.rs

1use std::{fs, path};
2
3use crate::v5;
4use crate::{Error, ErrorKind, Result};
5
6#[macro_export]
7macro_rules! config_field {
8    ($table:ident, $field:ident, $config:ident, $($args:tt)+) => {{
9        let field = stringify!($field);
10        if let Some(val) = $table.get(field) {
11            $config.$field = match val.$($args)+ {
12                Some(val) => val.parse()?,
13                None => err!(
14                    InvalidInput,
15                    desc: "invalid config field {}, {}", field, val.to_string()
16                )?,
17            }
18        }
19    }};
20    (opt: $table:ident, $field:ident, $config:ident, $($args:tt)+) => {{
21        let field = stringify!($field);
22        if let Some(val) = $table.get(field) {
23            $config.$field = match val.$($args)+ {
24                Some(val) => Some(val.parse()?),
25                None => err!(
26                    InvalidInput,
27                    desc: "invalid config field {}, {}", field, val.to_string()
28                )?,
29            }
30        }
31    }};
32}
33
34/// Configuration for broker and supported protocols.
35#[derive(Clone, Eq, PartialEq)]
36pub struct Config {
37    /// Broker configuration.
38    #[cfg(feature = "broker")]
39    pub broker: crate::broker::Config,
40
41    /// Protocol configuration for MQTT V5.
42    pub mqtt_v5: v5::Config,
43}
44
45impl Default for Config {
46    fn default() -> Config {
47        Config {
48            #[cfg(feature = "broker")]
49            broker: crate::broker::Config::default(),
50            mqtt_v5: v5::Config::default(),
51        }
52    }
53}
54
55impl TryFrom<toml::Value> for Config {
56    type Error = Error;
57
58    fn try_from(val: toml::Value) -> Result<Config> {
59        let config = match val.as_table() {
60            Some(map) => Config {
61                #[cfg(feature = "broker")]
62                broker: match map.get("broker") {
63                    Some(value) => crate::broker::Config::try_from(value.clone())?,
64                    None => crate::broker::Config::default(),
65                },
66                mqtt_v5: match map.get("mqtt_v5") {
67                    Some(value) => v5::Config::try_from(value.clone())?,
68                    None => v5::Config::default(),
69                },
70            },
71            None => err!(InvalidInput, desc: "invalid toml configuration")?,
72        };
73        Ok(config)
74    }
75}
76
77impl Config {
78    /// Construct a new configuration from a file located by `loc`.
79    pub fn from_file<P>(loc: P) -> Result<Config>
80    where
81        P: AsRef<path::Path>,
82    {
83        use std::str::from_utf8;
84
85        let ploc: &path::Path = loc.as_ref();
86
87        let value: toml::Value = {
88            let data = err!(IOError, try: fs::read(ploc), "reading config {:?}", ploc)?;
89            let txt = err!(InvalidInput, try: from_utf8(&data), "bad config {:?}", ploc)?;
90            err!(InvalidInput, try: toml::from_str(txt), "config not toml {:?}", ploc)?
91        };
92
93        Config::try_from(value)
94    }
95
96    /// Validate configuration
97    pub fn validate(&self) -> Result<()> {
98        #[cfg(feature = "broker")]
99        self.broker.validate()?;
100
101        self.mqtt_v5.validate()?;
102        Ok(())
103    }
104}