//! # Configuration //! //! This module defines the configuration used to initialize both proxies. use log::error; use std::env; use std::fmt::Debug; use std::sync::Arc; use thiserror::Error; #[derive(Error, Debug)] pub enum Error { #[error("Environment variable {0} not set.")] MissingEnvVar(String), #[error("Failed to parse {0}.")] ParseError(String), } /// Configuration for any proxy #[derive(Debug)] pub struct Proxy { pub local_port: u16, pub bind_address: String, pub remote_host: String, pub remote_port: u16, pub protocol: &'static str, } /// Aggregated configuration for both proxies, already in a reference counter. pub struct Configuration { pub imap_configuration: Arc, pub smtp_configuration: Arc, } impl Configuration { /// Creates a new configuration object by reading the environment /// variables. Exits if the right ones aren't found. pub fn new() -> Result { Ok(Configuration { imap_configuration: Arc::new(Proxy { local_port: get_env_number("LOCAL_IMAP_PORT", 143)?, bind_address: get_env_var("LOCAL_IMAP_BIND_ADDRESS", Some("0.0.0.0".to_string()))?, remote_host: get_env_var("REMOTE_IMAP_HOST", None)?, remote_port: get_env_number("REMOTE_IMAP_PORT", 993)?, protocol: "IMAP", }), smtp_configuration: Arc::new(Proxy { local_port: get_env_number("LOCAL_SMTP_PORT", 25)?, bind_address: get_env_var("LOCAL_SMTP_BIND_ADDRESS", Some("0.0.0.0".to_string()))?, remote_host: get_env_var("REMOTE_SMTP_HOST", None)?, remote_port: get_env_number("REMOTE_SMTP_PORT", 465)?, protocol: "SMTP", }), }) } } /// Get an environment variable or return an error. fn get_env_var(name: &str, default: Option) -> Result { match env::var(name) { Ok(value) => Ok(value), Err(_) => match default { Some(default_value) => Ok(default_value), None => Err(Error::MissingEnvVar(name.to_string())), }, } } /// Get an environment variable and parse it as a number. Return a default /// if not set. fn get_env_number(name: &str, default: u16) -> Result { match env::var(name) { Ok(value) => value .parse() .map_err(|_| Error::ParseError(name.to_string())), Err(_) => Ok(default), } }