movey_utils/
app_config.rs

1use config::{Config, Environment};
2use std::ops::Deref;
3use std::sync::RwLock;
4use lazy_static::lazy_static;
5use serde::Deserialize;
6
7use super::error::Result;
8
9// CONFIG static variable. It's actually an AppConfig
10// inside an RwLock.
11lazy_static! {
12    static ref CONFIG: RwLock<Config> = RwLock::new(Config::new());
13}
14
15#[derive(Debug, Deserialize)]
16pub struct Database {
17    pub url: String,
18}
19
20#[derive(Debug, Deserialize)]
21pub struct AppConfig {
22    pub debug: bool,
23    pub database: Database,
24}
25
26impl AppConfig {
27    pub fn init(default_config: Option<&str>) -> Result<()> {
28        let mut settings = Config::new();
29
30        // Embed file into executable
31        // This macro will embed the configuration file into the
32        // executable. Check include_str! for more info.
33        if let Some(config_contents) = default_config {
34            //let contents = include_str!(config_file_path);
35            settings.merge(config::File::from_str(&config_contents, config::FileFormat::Toml))?;
36        }
37
38        // Merge settings with env variables
39        settings.merge(Environment::with_prefix("APP"))?;
40
41        // TODO: Merge settings with Clap Settings Arguments
42
43        // Save Config to RwLoc
44        {
45            let mut w = CONFIG.write()?;
46            *w = settings;
47        }
48
49        Ok(())
50    }
51
52    pub fn merge_config(config_file: Option<&str>) -> Result<()> {
53        // Merge settings with config file if there is one
54        if let Some(config_file_path) = config_file {
55            {
56                CONFIG
57                    .write()?
58                    .merge(config::File::with_name(config_file_path))?;
59            }
60        }
61        Ok(())
62    }
63
64    // Set CONFIG
65    pub fn set(key: &str, value: &str) -> Result<()> {
66        {
67            // Set Property
68            CONFIG.write()?.set(key, value)?;
69        }
70
71        Ok(())
72    }
73
74    // Get a single value
75    pub fn get<'de, T>(key: &'de str) -> Result<T>
76    where
77        T: serde::Deserialize<'de>,
78    {
79        Ok(CONFIG.read()?.get::<T>(key)?)
80    }
81
82    // Get CONFIG
83    // This clones Config (from RwLock<Config>) into a new AppConfig object.
84    // This means you have to fetch this again if you changed the configuration.
85    pub fn fetch() -> Result<AppConfig> {
86        // Get a Read Lock from RwLock
87        let r = CONFIG.read()?;
88
89        // Clone the Config object
90        let config_clone = r.deref().clone();
91
92        // Coerce Config into AppConfig
93        Ok(config_clone.try_into()?)
94    }
95}