Skip to main content

neda_lib/client/
config_reader.rs

1use gtoml::{get, parse};
2use std::{env, fs, path::Path};
3
4#[derive(Debug)]
5pub struct ApiConfig {
6    pub city: String,
7    pub country: String,
8}
9
10#[derive(Debug)]
11pub struct AdhanConfig {
12    pub enabled: bool,
13    pub file: String,
14}
15
16#[derive(Debug)]
17pub struct DbConfig {
18    pub path: String,
19}
20
21#[derive(Debug)]
22pub struct Config {
23    pub api: ApiConfig,
24    pub adhan: AdhanConfig,
25    pub db: DbConfig,
26}
27
28#[derive(Debug)]
29pub enum ConfigError {
30    Io(std::io::Error),
31    ParseError(String),
32    MissingField(String),
33}
34
35impl Config {
36    pub fn load() -> Result<Self, ConfigError> {
37        let config_dir_path = match env::var("XDG_CONFIG_HOME") {
38            Ok(path) => path + "/neda",
39            Err(_) => env::var("HOME").unwrap() + "/.config/neda",
40        };
41
42        let data_dir_path = match env::var("XDG_DATA_HOME") {
43            Ok(path) => path + "/neda",
44            Err(_) => env::var("HOME").unwrap() + "/.local/share/neda",
45        };
46
47        fs::create_dir_all(&config_dir_path).map_err(ConfigError::Io)?;
48        fs::create_dir_all(&data_dir_path).map_err(ConfigError::Io)?;
49
50        let config_path = config_dir_path + "/config.toml";
51
52        const DEFAULT_CONFIG: &str = include_str!("../../assets/templetes/config.toml");
53
54        if !Path::new(&config_path).exists() {
55            fs::write(&config_path, DEFAULT_CONFIG).map_err(ConfigError::Io)?;
56        }
57
58        let config: String = fs::read_to_string(&config_path).map_err(ConfigError::Io)?;
59        let config = parse(&config).map_err(|e| ConfigError::ParseError(e.to_string()))?;
60
61        Ok(Config {
62            api: ApiConfig {
63                city: match get(&config, "api.city")
64                    .map_err(|e| ConfigError::ParseError(e.to_string()))?
65                {
66                    Some(value) => value
67                        .as_str()
68                        .ok_or_else(|| {
69                            ConfigError::ParseError("api.city is not a string".to_string())
70                        })?
71                        .to_string(),
72                    None => {
73                        return Err(ConfigError::MissingField(
74                            "api.city is not set in config.toml".to_string(),
75                        ));
76                    }
77                },
78                country: match get(&config, "api.country")
79                    .map_err(|e| ConfigError::ParseError(e.to_string()))?
80                {
81                    Some(value) => value
82                        .as_str()
83                        .ok_or_else(|| {
84                            ConfigError::ParseError("api.country is not a string".to_string())
85                        })?
86                        .to_string(),
87                    None => {
88                        return Err(ConfigError::MissingField(
89                            "api.country is not set in config.toml".to_string(),
90                        ));
91                    }
92                },
93            },
94            adhan: AdhanConfig {
95                enabled: match get(&config, "adhan.enabled")
96                    .map_err(|e| ConfigError::ParseError(e.to_string()))?
97                {
98                    Some(value) => value.as_bool().ok_or_else(|| {
99                        ConfigError::ParseError("adhan.enabled is not a boolean".to_string())
100                    })?,
101                    None => {
102                        return Err(ConfigError::MissingField(
103                            "adhan.enabled is not set in config.toml".to_string(),
104                        ));
105                    }
106                },
107                file: match get(&config, "adhan.file")
108                    .map_err(|e| ConfigError::ParseError(e.to_string()))?
109                {
110                    Some(value) => value
111                        .as_str()
112                        .ok_or_else(|| {
113                            ConfigError::ParseError("adhan.file is not a string".to_string())
114                        })?
115                        .to_string(),
116                    None => {
117                        return Err(ConfigError::MissingField(
118                            "adhan.file is not set in config.toml".to_string(),
119                        ));
120                    }
121                },
122            },
123            db: DbConfig {
124                path: match get(&config, "db.path")
125                    .map_err(|e| ConfigError::ParseError(e.to_string()))?
126                {
127                    Some(value) => value
128                        .as_str()
129                        .ok_or_else(|| {
130                            ConfigError::ParseError("db.path is not a string".to_string())
131                        })?
132                        .to_string(),
133                    None => {
134                        return Err(ConfigError::MissingField(
135                            "db.path is not set in config.toml".to_string(),
136                        ));
137                    }
138                },
139            },
140        })
141    }
142}