diff options
author | Felix Ableitner <me@nutomic.com> | 2019-12-15 17:40:55 +0100 |
---|---|---|
committer | Felix Ableitner <me@nutomic.com> | 2019-12-27 17:28:44 +0100 |
commit | cf3ae15ee9289fa4030828363158b02facbab1bb (patch) | |
tree | ec4d1973f62185624fdd570267a6a73d7e3285ba /server/src | |
parent | 34def84d4307d1f4d822091a35d94ab090c558af (diff) |
Implement config (fixes #351)
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/api/mod.rs | 2 | ||||
-rw-r--r-- | server/src/api/user.rs | 3 | ||||
-rw-r--r-- | server/src/db/mod.rs | 4 | ||||
-rw-r--r-- | server/src/feeds.rs | 2 | ||||
-rw-r--r-- | server/src/lib.rs | 88 | ||||
-rw-r--r-- | server/src/main.rs | 2 | ||||
-rw-r--r-- | server/src/settings.rs | 104 | ||||
-rw-r--r-- | server/src/websocket/server.rs | 12 |
8 files changed, 121 insertions, 96 deletions
diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index 97a11900..07712e87 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -15,7 +15,7 @@ use crate::db::user_mention::*; use crate::db::user_mention_view::*; use crate::db::user_view::*; use crate::db::*; -use crate::{extract_usernames, has_slurs, naive_from_unix, naive_now, remove_slurs, Settings}; +use crate::{extract_usernames, has_slurs, naive_from_unix, naive_now, remove_slurs}; use failure::Error; use serde::{Deserialize, Serialize}; diff --git a/server/src/api/user.rs b/server/src/api/user.rs index df38dc99..9a343427 100644 --- a/server/src/api/user.rs +++ b/server/src/api/user.rs @@ -1,4 +1,5 @@ use super::*; +use crate::settings::Settings; use crate::{generate_random_string, send_email}; use bcrypt::verify; use std::str::FromStr; @@ -217,7 +218,7 @@ impl Perform<LoginResponse> for Oper<Register> { // Register the new user let user_form = UserForm { name: data.username.to_owned(), - fedi_name: Settings::get().hostname.into(), + fedi_name: Settings::get().hostname.to_owned(), email: data.email.to_owned(), password_encrypted: data.password.to_owned(), preferred_username: None, diff --git a/server/src/db/mod.rs b/server/src/db/mod.rs index a7961f12..5d3a0920 100644 --- a/server/src/db/mod.rs +++ b/server/src/db/mod.rs @@ -1,4 +1,4 @@ -use crate::Settings; +use crate::settings::Settings; use diesel::dsl::*; use diesel::result::Error; use diesel::*; @@ -110,7 +110,7 @@ impl<T> MaybeOptional<T> for Option<T> { } pub fn establish_connection() -> PgConnection { - let db_url = Settings::get().db_url; + let db_url = Settings::get().get_database_url(); PgConnection::establish(&db_url).expect(&format!("Error connecting to {}", db_url)) } diff --git a/server/src/feeds.rs b/server/src/feeds.rs index a16116d4..5337edcf 100644 --- a/server/src/feeds.rs +++ b/server/src/feeds.rs @@ -331,7 +331,7 @@ fn create_post_items(posts: Vec<PostView>) -> Vec<Item> { "/c/{} <a href=\"{}\">(link)</a>", p.community_name, community_url )) - .domain(Settings::get().hostname) + .domain(Settings::get().hostname.to_owned()) .build(); i.categories(vec![category.unwrap()]); diff --git a/server/src/lib.rs b/server/src/lib.rs index b560edf4..c23c97d2 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -28,11 +28,12 @@ pub mod db; pub mod feeds; pub mod nodeinfo; pub mod schema; +pub mod settings; pub mod version; pub mod websocket; +use crate::settings::Settings; use chrono::{DateTime, NaiveDateTime, Utc}; -use dotenv::dotenv; use lettre::smtp::authentication::{Credentials, Mechanism}; use lettre::smtp::extension::ClientId; use lettre::smtp::ConnectionReuseParameters; @@ -41,87 +42,6 @@ use lettre_email::Email; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; use regex::Regex; -use std::env; -use std::net::IpAddr; - -pub struct Settings { - pub db_url: String, - pub hostname: String, - pub bind: IpAddr, - pub port: u16, - pub jwt_secret: String, - pub rate_limit_message: i32, - pub rate_limit_message_per_second: i32, - pub rate_limit_post: i32, - pub rate_limit_post_per_second: i32, - pub rate_limit_register: i32, - pub rate_limit_register_per_second: i32, - pub email_config: Option<EmailConfig>, -} - -pub struct EmailConfig { - smtp_server: String, - smtp_login: String, - smtp_password: String, - smtp_from_address: String, -} - -impl Settings { - pub fn get() -> Self { - dotenv().ok(); - - let email_config = - if env::var("SMTP_SERVER").is_ok() && !env::var("SMTP_SERVER").unwrap().eq("") { - Some(EmailConfig { - smtp_server: env::var("SMTP_SERVER").expect("SMTP_SERVER must be set"), - smtp_login: env::var("SMTP_LOGIN").expect("SMTP_LOGIN must be set"), - smtp_password: env::var("SMTP_PASSWORD").expect("SMTP_PASSWORD must be set"), - smtp_from_address: env::var("SMTP_FROM_ADDRESS").expect("SMTP_FROM_ADDRESS must be set"), - }) - } else { - None - }; - - Settings { - db_url: env::var("DATABASE_URL").expect("DATABASE_URL must be set"), - hostname: env::var("HOSTNAME").unwrap_or("rrr".to_string()), - bind: env::var("BIND") - .unwrap_or("0.0.0.0".to_string()) - .parse() - .unwrap(), - port: env::var("PORT") - .unwrap_or("8536".to_string()) - .parse() - .unwrap(), - jwt_secret: env::var("JWT_SECRET").unwrap_or("changeme".to_string()), - rate_limit_message: env::var("RATE_LIMIT_MESSAGE") - .unwrap_or("30".to_string()) - .parse() - .unwrap(), - rate_limit_message_per_second: env::var("RATE_LIMIT_MESSAGE_PER_SECOND") - .unwrap_or("60".to_string()) - .parse() - .unwrap(), - rate_limit_post: env::var("RATE_LIMIT_POST") - .unwrap_or("3".to_string()) - .parse() - .unwrap(), - rate_limit_post_per_second: env::var("RATE_LIMIT_POST_PER_SECOND") - .unwrap_or("600".to_string()) - .parse() - .unwrap(), - rate_limit_register: env::var("RATE_LIMIT_REGISTER") - .unwrap_or("1".to_string()) - .parse() - .unwrap(), - rate_limit_register_per_second: env::var("RATE_LIMIT_REGISTER_PER_SECOND") - .unwrap_or("3600".to_string()) - .parse() - .unwrap(), - email_config, - } - } -} pub fn to_datetime_utc(ndt: NaiveDateTime) -> DateTime<Utc> { DateTime::<Utc>::from_utc(ndt, Utc) @@ -171,13 +91,13 @@ pub fn send_email( to_username: &str, html: &str, ) -> Result<(), String> { - let email_config = Settings::get().email_config.ok_or("no_email_setup")?; + let email_config = Settings::get().email.as_ref().ok_or("no_email_setup")?; let email = Email::builder() .to((to_email, to_username)) .from(( email_config.smtp_login.to_owned(), - email_config.smtp_from_address, + email_config.smtp_from_address.to_owned(), )) .subject(subject) .html(html) diff --git a/server/src/main.rs b/server/src/main.rs index d19ef777..2d657a61 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -10,8 +10,8 @@ use lemmy_server::apub; use lemmy_server::db::establish_connection; use lemmy_server::feeds; use lemmy_server::nodeinfo; +use lemmy_server::settings::Settings; use lemmy_server::websocket::server::*; -use lemmy_server::Settings; use std::env; use std::time::{Duration, Instant}; diff --git a/server/src/settings.rs b/server/src/settings.rs new file mode 100644 index 00000000..77497631 --- /dev/null +++ b/server/src/settings.rs @@ -0,0 +1,104 @@ +extern crate lazy_static; +use config::{Config, ConfigError, Environment, File}; +use serde::Deserialize; +use std::env; +use std::net::IpAddr; + +static CONFIG_FILE_DEFAULTS: &str = "config/defaults.hjson"; +static CONFIG_FILE_COSTUMIZED: &str = "config/custom.hjson"; + +#[derive(Debug, Deserialize)] +pub struct Settings { + pub database: Database, + pub hostname: String, + pub bind: IpAddr, + pub port: u16, + pub jwt_secret: String, + pub rate_limit: RateLimitConfig, + pub email: Option<EmailConfig>, +} + +#[derive(Debug, Deserialize)] +pub struct RateLimitConfig { + pub message: i32, + pub message_per_second: i32, + pub post: i32, + pub post_per_second: i32, + pub register: i32, + pub register_per_second: i32, +} + +#[derive(Debug, Deserialize)] +pub struct EmailConfig { + pub smtp_server: String, + pub smtp_login: String, + pub smtp_password: String, + pub smtp_from_address: String, +} + +#[derive(Debug, Deserialize)] +pub struct Database { + pub user: String, + pub password: String, + pub host: String, + pub port: i32, + pub database: String, +} + +lazy_static! { + static ref SETTINGS: Settings = { + return match Settings::init() { + Ok(c) => c, + Err(e) => panic!("{}", e), + }; + }; +} + +impl Settings { + + /// Reads config from the files and environment. + /// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten + /// from CONFIG_FILE_COSTUMIZED (optional). Finally, values from the environment + /// (with prefix LEMMY) are added to the config. + fn init() -> Result<Self, ConfigError> { + let mut s = Config::new(); + + // Start off by merging in the "default" configuration file + s.merge(File::with_name(CONFIG_FILE_DEFAULTS))?; + + // TODO: we could also automatically load dev/prod configs based on environment + // https://github.com/mehcode/config-rs/blob/master/examples/hierarchical-env/src/settings.rs#L49 + s.merge(File::with_name(CONFIG_FILE_COSTUMIZED).required(false))?; + + // Add in settings from the environment (with a prefix of LEMMY) + // Eg.. `LEMMY_DEBUG=1 ./target/app` would set the `debug` key + s.merge(Environment::with_prefix("LEMMY"))?; + + return s.try_into(); + } + + /// Returns the config as a struct. + pub fn get() -> &'static Self { + &SETTINGS + } + + /// Returns the postgres connection url. If LEMMY_DATABASE_URL is set, that is used, + /// otherwise the connection url is generated from the config. + pub fn get_database_url(&self) -> String { + match env::var("LEMMY_DATABASE_URL") { + Ok(url) => url, + Err(_) => format!( + "postgres://{}:{}@{}:{}/{}", + self.database.user, + self.database.password, + self.database.host, + self.database.port, + self.database.database + ), + } + } + + pub fn api_endpoint(&self) -> String { + format!("{}/api/v1", self.hostname) + } +} diff --git a/server/src/websocket/server.rs b/server/src/websocket/server.rs index 86a929c9..56fff275 100644 --- a/server/src/websocket/server.rs +++ b/server/src/websocket/server.rs @@ -152,24 +152,24 @@ impl ChatServer { fn check_rate_limit_register(&mut self, id: usize) -> Result<(), Error> { self.check_rate_limit_full( id, - Settings::get().rate_limit_register, - Settings::get().rate_limit_register_per_second, + Settings::get().rate_limit.register, + Settings::get().rate_limit.register_per_second, ) } fn check_rate_limit_post(&mut self, id: usize) -> Result<(), Error> { self.check_rate_limit_full( id, - Settings::get().rate_limit_post, - Settings::get().rate_limit_post_per_second, + Settings::get().rate_limit.post, + Settings::get().rate_limit.post_per_second, ) } fn check_rate_limit_message(&mut self, id: usize) -> Result<(), Error> { self.check_rate_limit_full( id, - Settings::get().rate_limit_message, - Settings::get().rate_limit_message_per_second, + Settings::get().rate_limit.message, + Settings::get().rate_limit.message_per_second, ) } |