alfred_core/
config.rs

1use std::collections::HashMap;
2use serde_derive::Deserialize;
3use std::fs;
4use std::path::Path;
5use toml;
6use envconfig::Envconfig;
7use toml::{Table, Value};
8
9pub const CONFIG_FILENAME: &str = "config.toml";
10const DEFAULT_TMP_DIR: &str = "/tmp";
11
12#[derive(Deserialize, Debug)]
13pub struct Config {
14    pub alfred: AlfredConfig,
15    module: HashMap<String, String>
16}
17
18impl Config {
19    pub fn read(module_name: Option<&str>) -> Self {
20        let alfred = Self::read_alfred_config();
21        let module = module_name.map_or_else(HashMap::new, Self::read_module_config);
22        Self { alfred, module }
23    }
24
25    fn read_module_config(module_name: &str) -> HashMap<String, String> {
26        let contents = fs::read_to_string(CONFIG_FILENAME).expect("Could not read file");
27        let table: Table = contents.parse().expect("Could not parse toml file");
28        table.get(&module_name.to_string())
29            .and_then(Value::as_table)
30            .map_or_else(HashMap::new, |module_config| module_config
31                .iter()
32                .map(|(k, v)| (k.to_string(), v.as_str().unwrap_or("").to_string()))
33                .collect())
34    }
35
36    fn read_alfred_config() -> AlfredConfig {
37        let from_env = EnvConfig::from_env();
38        let from_file_config = FromFileConfig::read();
39        let url = from_env.alfred.url.unwrap_or(from_file_config.alfred.url);
40        let pub_port = from_env.alfred.pub_port.unwrap_or(from_file_config.alfred.pub_port);
41        let sub_port = from_env.alfred.sub_port.unwrap_or(from_file_config.alfred.sub_port);
42        let tmp_dir = from_env.alfred.tmp_dir
43            .or(from_file_config.alfred.tmp_dir)
44            .unwrap_or_else(|| DEFAULT_TMP_DIR.to_string());
45        AlfredConfig { url, pub_port, sub_port, tmp_dir, modules: from_file_config.alfred.modules }
46    }
47
48    pub fn get_alfred_pub_url(&self) -> String {
49        format!("{}:{}", self.alfred.url, self.alfred.pub_port)
50    }
51    pub fn get_alfred_sub_url(&self) -> String {
52        format!("{}:{}", self.alfred.url, self.alfred.sub_port)
53    }
54    pub fn get_module_value(&self, key: &str) -> Option<String> {
55        self.module.get(key).cloned()
56    }
57}
58
59#[derive(Deserialize, Debug)]
60pub struct AlfredConfig {
61    pub url: String,
62    pub pub_port: u32,
63    pub sub_port: u32,
64    pub tmp_dir: String,
65    pub modules: Vec<String>
66}
67
68#[derive(Deserialize, Debug)]
69struct FromFileConfig {
70    alfred: FromFileAlfredConfig
71}
72
73impl FromFileConfig {
74
75    fn get_config_filename() -> String {
76        std::env::var("ALFRED_CONFIG")
77            .ok()
78            .and_then(|path| Path::new(&path.as_str()).exists().then_some(path))
79            .unwrap_or_else(|| CONFIG_FILENAME.to_string())
80    }
81
82    fn read() -> Self {
83        let contents = fs::read_to_string(Self::get_config_filename()).expect("Could not read file");
84        toml::from_str(&contents).expect("Unable to load data")
85    }
86}
87
88#[derive(Deserialize, Debug)]
89struct FromFileAlfredConfig {
90    url: String,
91    pub_port: u32,
92    sub_port: u32,
93    tmp_dir: Option<String>,
94    #[serde(default)]
95    modules: Vec<String>
96}
97
98#[derive(Deserialize, Debug)]
99struct EnvConfig {
100    alfred: EnvAlfredConfig,
101}
102impl EnvConfig {
103
104    fn from_env() -> Self {
105        Self {
106            alfred: EnvAlfredConfig::init_from_env().expect("Error during initialization using env variable"),
107        }
108    }
109}
110
111#[derive(Deserialize, Debug, Envconfig)]
112struct EnvAlfredConfig {
113    #[envconfig(from = "ALFRED_URL")]
114    url: Option<String>,
115    #[envconfig(from = "ALFRED_PUB_PORT")]
116    pub_port: Option<u32>,
117    #[envconfig(from = "ALFRED_SUB_PORT")]
118    sub_port: Option<u32>,
119    #[envconfig(from = "ALFRED_TMP_DIR")]
120    tmp_dir: Option<String>
121}