schnecke/
config.rs

1extern crate yaml_rust;
2
3use super::constants::{APP_NAME, DIR_NAME};
4use std::collections::HashMap;
5
6use std::clone::Clone;
7use std::fs;
8use std::path::PathBuf;
9use std::result::Result;
10use yaml_rust::{Yaml, YamlLoader};
11
12use log::info;
13
14pub struct ServerConfig {
15    pub port: u16,
16    pub use_unix_domain_socket: bool,
17    pub use_ssl: bool,
18}
19
20impl ServerConfig {
21    fn new(port: u16, use_unix_domain_socket: bool, use_ssl: bool) -> ServerConfig {
22        ServerConfig {
23            port: port,
24            use_unix_domain_socket: use_unix_domain_socket,
25            use_ssl: use_ssl,
26        }
27    }
28}
29
30#[derive(Clone)]
31pub struct CacheConfig {
32    /// cache.m0cchi.net:3000
33    pub host: String,
34    /// https://contents.m0cchi.net
35    pub origin: String,
36    pub expire: u32,
37    pub err_expire: u32,
38    pub keep_cache_after_shutdown: bool,
39}
40
41impl CacheConfig {
42    fn new(
43        host: &str,
44        origin: &str,
45        expire: u32,
46        err_expire: u32,
47        keep_cache_after_shutdown: bool,
48    ) -> CacheConfig {
49        CacheConfig {
50            host: host.to_string(),
51            origin: origin.to_string(),
52            expire: expire,
53            err_expire: err_expire,
54            keep_cache_after_shutdown: keep_cache_after_shutdown,
55        }
56    }
57}
58
59pub struct Config {
60    pub server: ServerConfig,
61    pub cache: HashMap<String, CacheConfig>,
62}
63
64fn i64tou32(i: i64) -> Result<u32, &'static str> {
65    if i <= u32::max_value() as i64 && i >= 0 {
66        Ok(i as u32)
67    } else {
68        Err("error!")
69    }
70}
71
72fn collect_config_path(home: &PathBuf) -> Result<PathBuf, String> {
73    let candidate = vec![
74        format!(".{}{}", APP_NAME, ".yml"),
75        format!(".{}{}", APP_NAME, ".yaml"),
76        format!("{}/{}{}", DIR_NAME, APP_NAME, ".yml"),
77        format!("{}/{}{}", DIR_NAME, APP_NAME, ".yaml"),
78    ];
79    for c in &candidate {
80        let config_path = home.join(c);
81        if config_path.exists() {
82            return Ok(config_path);
83        }
84    }
85    Err(format!("missing {:?}", candidate))
86}
87
88pub fn load_config_file(home: &PathBuf) -> Result<Config, String> {
89    let config_path = match collect_config_path(home) {
90        Ok(v) => v,
91        Err(err) => {
92            return Err(err.to_string());
93        }
94    };
95    info!(
96        "load config file: {}",
97        config_path
98            .to_str()
99            .expect("error: can't load config file")
100    );
101
102    let yaml_text = fs::read_to_string(config_path).unwrap();
103    let yaml = YamlLoader::load_from_str(yaml_text.as_str()).unwrap();
104    let hosts = &yaml[0]["hosts"];
105    let default = &hosts["default"];
106    let mut cache_config: HashMap<String, CacheConfig> = HashMap::new();
107    match hosts {
108        Yaml::Hash(hosts) => {
109            for (host, config) in hosts {
110                let host = host.as_str().unwrap();
111                if host != "default" {
112                    let origin = match &config["origin"] {
113                        Yaml::String(origin) => origin,
114                        _ => {
115                            return Err(format!("parse error:\n\thost:{}\n\tstep:origin", host));
116                        }
117                    };
118                    let expire: u32 = match config["expire"] {
119                        Yaml::Integer(expire) => match i64tou32(expire) {
120                            Ok(v) => v,
121                            Err(_) => {
122                                return Err(format!(
123                                    "parse error:\n\thost:{}\n\tstep:expire",
124                                    host
125                                ));
126                            }
127                        },
128                        _ => match default["expire"] {
129                            Yaml::Integer(expire) => match i64tou32(expire) {
130                                Ok(v) => v,
131                                Err(_) => {
132                                    return Err(format!(
133                                        "parse error:\n\thost:{}\n\tstep:expire",
134                                        host
135                                    ));
136                                }
137                            },
138                            _ => 86400,
139                        },
140                    };
141                    let err_expire: u32 = match config["err_expire"] {
142                        Yaml::Integer(expire) => match i64tou32(expire) {
143                            Ok(v) => v,
144                            Err(_) => {
145                                return Err(format!(
146                                    "parse error:\n\thost:{}\n\tstep:err_expire",
147                                    host
148                                ));
149                            }
150                        },
151                        _ => match default["err_expire"] {
152                            Yaml::Integer(expire) => match i64tou32(expire) {
153                                Ok(v) => v,
154                                Err(_) => {
155                                    return Err(format!(
156                                        "parse error:\n\thost:{}\n\tstep:err_expire",
157                                        host
158                                    ));
159                                }
160                            },
161                            _ => 300,
162                        },
163                    };
164                    let keep_cache_after_shutdown = match config["keep_cache_after_shutdown"] {
165                        Yaml::Boolean(keep_cache_after_shutdown) => keep_cache_after_shutdown,
166                        _ => match default["keep_cache_after_shutdown"] {
167                            Yaml::Boolean(keep_cache_after_shutdown) => keep_cache_after_shutdown,
168                            _ => false,
169                        },
170                    };
171                    let config = CacheConfig::new(
172                        &host,
173                        &origin,
174                        expire,
175                        err_expire,
176                        keep_cache_after_shutdown,
177                    );
178                    cache_config.insert(host.to_string(), config);
179                }
180            }
181        }
182        _ => {}
183    }
184
185    let server_config = ServerConfig::new(0, false, false);
186    let config = Config {
187        server: server_config,
188        cache: cache_config,
189    };
190    Ok(config)
191}