· 6 years ago · Mar 06, 2019, 04:54 PM
1pub mod config {
2 use std::convert::From;
3 use std::env;
4 use std::error::Error;
5 use std::fmt::{self, Display, Formatter};
6 use std::result;
7
8 use num_cpus;
9 use rand::{self, Rng};
10 use rocket;
11
12 macro_rules! env_name {
13 ($name:expr) => {
14 concat!("__", $name)
15 };
16 }
17
18 #[derive(Debug)]
19 pub struct Config {
20 pub secrets_path: String,
21 pub salt: String,
22
23 pub environment: rocket::config::Environment,
24 pub log_level: rocket::config::LoggingLevel,
25 pub address: String,
26 pub port: u16,
27 pub keep_alive: u32,
28 pub workers: u16,
29 pub secret_key: String,
30 }
31
32 impl Default for Config {
33 fn default() -> Self {
34 let secret_key: String = rand::thread_rng()
35 .sample_iter(&rand::distributions::Alphanumeric)
36 .take(32)
37 .collect();
38
39 let secret_key = base64::encode(&secret_key);
40
41 Self {
42 secrets_path: String::from("./secrets"),
43 salt: String::new(),
44
45 environment: rocket::config::Environment::Development,
46 log_level: rocket::config::LoggingLevel::Normal,
47 keep_alive: 5,
48 address: String::from("0.0.0.0"),
49 port: 8000,
50 workers: (num_cpus::get() * 2) as u16,
51 secret_key,
52 }
53 }
54 }
55
56 impl Config {
57 pub fn new() -> Self {
58 Default::default()
59 }
60
61 fn parse_environment(env: &str) -> Option<rocket::config::Environment> {
62 match env {
63 "development" | "dev" => Some(rocket::config::Environment::Development),
64 "production" | "prod" => Some(rocket::config::Environment::Production),
65 "staging" | "stag" => Some(rocket::config::Environment::Staging),
66 _ => None,
67 }
68 }
69
70 fn parse_log_level(log_level: &str) -> Option<rocket::config::LoggingLevel> {
71 match log_level.to_lowercase().as_str() {
72 "off" | "0" | "none" => Some(rocket::config::LoggingLevel::Off),
73 "normal" | "1" => Some(rocket::config::LoggingLevel::Normal),
74 "critical" | "2" => Some(rocket::config::LoggingLevel::Critical),
75 "debug" | "3" => Some(rocket::config::LoggingLevel::Debug),
76 _ => None,
77 }
78 }
79
80 fn emit_warnings_maybe(&self) {
81 if self.salt.is_empty() {
82 println!("You didn't provide salt. It's not safe to do so.");
83 }
84 }
85 }
86
87 impl From<env::Vars> for Config {
88 fn from(vars: env::Vars) -> Self {
89 let mut config = Self::new();
90
91 for (key, value) in vars {
92 match key.as_str() {
93 env_name!("SECRETS_PATH") => config.secrets_path = value,
94 env_name!("SALT") => config.salt = value,
95 env_name!("KEEP_ALIVE") => {
96 if let Ok(n) = value.parse::<u32>() {
97 config.keep_alive = n;
98 }
99 }
100 env_name!("ENVIRONMENT") => {
101 if let Some(env) = Config::parse_environment(&value) {
102 config.environment = env;
103 }
104 }
105 env_name!("LOG_LEVEL") => {
106 if let Some(log_level) = Config::parse_log_level(&value) {
107 config.log_level = log_level;
108 }
109 }
110 _ => {}
111 }
112 }
113
114 config.emit_warnings_maybe();
115
116 config
117 }
118 }
119
120 impl From<Config> for rocket::Config {
121 fn from(c: Config) -> Self {
122 Self::build(c.environment)
123 .address(c.address)
124 .port(c.port)
125 .workers(c.workers)
126 .secret_key(c.secret_key)
127 .log_level(c.log_level)
128 .keep_alive(c.keep_alive)
129 .unwrap()
130 }
131 }
132}