Rewrite merge code to fix tests

This commit is contained in:
Felix Ableitner 2021-02-22 18:57:15 +01:00
parent 62c9be5b56
commit 59cce4a1f5
6 changed files with 126 additions and 86 deletions

View file

@ -583,7 +583,9 @@ impl Perform for GetSiteConfig {
// Only let admins read this // Only let admins read this
is_admin(context.pool(), user.id).await?; is_admin(context.pool(), user.id).await?;
let config_hjson = Settings::read_config_file()?; // TODO: should make the response field optional?
// or include env vars, but then we cant really save it
let config_hjson = Settings::read_config_file().unwrap_or("".to_string());
Ok(GetSiteConfigResponse { config_hjson }) Ok(GetSiteConfigResponse { config_hjson })
} }

View file

@ -48,7 +48,7 @@ pub(in crate::settings) fn parse_from_env() -> SettingsOpt {
admin_username: env_var("SETUP__ADMIN_USERNAME"), admin_username: env_var("SETUP__ADMIN_USERNAME"),
admin_password: env_var("SETUP__ADMIN_PASSWORD"), admin_password: env_var("SETUP__ADMIN_PASSWORD"),
admin_email: Some(env_var("SETUP__ADMIN_EMAIL")), admin_email: Some(env_var("SETUP__ADMIN_EMAIL")),
site_name: env_var("SETUP__ADMIN_SITE_NAME"), site_name: env_var("SETUP__SITE_NAME"),
}), }),
database: Some(DatabaseConfigOpt { database: Some(DatabaseConfigOpt {
user: env_var("DATABASE__USER"), user: env_var("DATABASE__USER"),

View file

@ -1,107 +1,141 @@
use crate::settings::{structs::*, structs_opt::*}; use crate::settings::{structs::*, structs_opt::*};
pub(in crate::settings) trait Merge<T> { pub(in crate::settings) trait Merge<T> {
fn merge(&mut self, opt: T); fn merge(self, opt: T) -> Self;
} }
impl Merge<SettingsOpt> for Settings { impl Merge<SettingsOpt> for Settings {
fn merge(&mut self, opt: SettingsOpt) { fn merge(self, opt: SettingsOpt) -> Self {
overwrite_if_some(&mut self.hostname, opt.hostname); Settings {
overwrite_if_some(&mut self.bind, opt.bind); setup: merge_structs(self.setup, opt.setup),
overwrite_if_some(&mut self.port, opt.port); database: merge_structs(self.database, opt.database),
overwrite_if_some(&mut self.tls_enabled, opt.tls_enabled); hostname: opt.hostname.unwrap_or(self.hostname),
overwrite_if_some(&mut self.jwt_secret, opt.jwt_secret); bind: opt.bind.unwrap_or(self.bind),
overwrite_if_some(&mut self.pictrs_url, opt.pictrs_url); port: opt.port.unwrap_or(self.port),
overwrite_if_some(&mut self.iframely_url, opt.iframely_url); tls_enabled: opt.tls_enabled.unwrap_or(self.tls_enabled),
merge_if_some(&mut self.captcha, opt.captcha); jwt_secret: opt.jwt_secret.unwrap_or(self.jwt_secret),
merge_if_some(&mut self.rate_limit, opt.rate_limit); pictrs_url: opt.pictrs_url.unwrap_or(self.pictrs_url),
merge_if_some_opt(&mut self.email, opt.email); iframely_url: opt.iframely_url.unwrap_or(self.iframely_url),
merge_if_some_opt(&mut self.setup, opt.setup); rate_limit: merge_structs(self.rate_limit, opt.rate_limit),
merge_if_some(&mut self.federation, opt.federation); email: merge_structs(self.email, opt.email),
merge_if_some(&mut self.database, opt.database); federation: merge_structs(self.federation, opt.federation),
captcha: merge_structs(self.captcha, opt.captcha),
}
} }
} }
impl Merge<RateLimitConfigOpt> for RateLimitConfig { impl Merge<RateLimitConfigOpt> for RateLimitConfig {
fn merge(&mut self, opt: RateLimitConfigOpt) { fn merge(self, opt: RateLimitConfigOpt) -> Self {
overwrite_if_some(&mut self.message, opt.message); RateLimitConfig {
overwrite_if_some(&mut self.message_per_second, opt.message_per_second); message: opt.message.unwrap_or(self.message),
overwrite_if_some(&mut self.post, opt.post); message_per_second: opt.message_per_second.unwrap_or(self.message_per_second),
overwrite_if_some(&mut self.post_per_second, opt.post_per_second); post: opt.post.unwrap_or(self.post),
overwrite_if_some(&mut self.register, opt.register); post_per_second: opt.post_per_second.unwrap_or(self.post_per_second),
overwrite_if_some(&mut self.register_per_second, opt.register_per_second); register: opt.register.unwrap_or(self.register),
overwrite_if_some(&mut self.image, opt.image); register_per_second: opt.register_per_second.unwrap_or(self.register_per_second),
overwrite_if_some(&mut self.image_per_second, opt.image_per_second); image: opt.image.unwrap_or(self.image),
image_per_second: opt.image_per_second.unwrap_or(self.image_per_second),
}
} }
} }
impl Merge<SetupOpt> for Setup { impl Merge<SetupOpt> for Option<Setup> {
fn merge(&mut self, opt: SetupOpt) { fn merge(self, opt: SetupOpt) -> Self {
overwrite_if_some(&mut self.admin_username, opt.admin_username); if let Some(setup) = self {
overwrite_if_some(&mut self.admin_password, opt.admin_password); Some(Setup {
overwrite_if_some(&mut self.admin_email, opt.admin_email); admin_username: opt.admin_username.unwrap_or(setup.admin_username),
overwrite_if_some(&mut self.site_name, opt.site_name); admin_password: opt.admin_password.unwrap_or(setup.admin_password),
admin_email: opt.admin_email.unwrap_or(setup.admin_email),
site_name: opt.site_name.unwrap_or(setup.site_name),
})
} else if let (Some(admin_username), Some(admin_password), Some(site_name)) =
(opt.admin_username, opt.admin_password, opt.site_name)
{
Some(Setup {
admin_username,
admin_password,
admin_email: opt.admin_email.flatten(),
site_name,
})
} else {
None
}
} }
} }
impl Merge<EmailConfigOpt> for EmailConfig { impl Merge<EmailConfigOpt> for Option<EmailConfig> {
fn merge(&mut self, opt: EmailConfigOpt) { fn merge(self, opt: EmailConfigOpt) -> Self {
overwrite_if_some(&mut self.smtp_server, opt.smtp_server); if let Some(email_config) = self {
overwrite_if_some(&mut self.smtp_login, opt.smtp_login); Some(EmailConfig {
overwrite_if_some(&mut self.smtp_password, opt.smtp_password); smtp_server: opt.smtp_server.unwrap_or(email_config.smtp_server),
overwrite_if_some(&mut self.smtp_from_address, opt.smtp_from_address); smtp_login: opt.smtp_login.unwrap_or(email_config.smtp_login),
overwrite_if_some(&mut self.use_tls, opt.use_tls); smtp_password: opt.smtp_password.unwrap_or(email_config.smtp_password),
smtp_from_address: opt
.smtp_from_address
.unwrap_or(email_config.smtp_from_address),
use_tls: opt.use_tls.unwrap_or(email_config.use_tls),
})
} else if let (Some(smtp_server), Some(smtp_from_address), Some(use_tls)) =
(opt.smtp_server, opt.smtp_from_address, opt.use_tls)
{
Some(EmailConfig {
smtp_server,
smtp_login: opt
.smtp_login
.or(self.clone().map(|s| s.smtp_login))
.flatten(),
smtp_password: opt
.smtp_password
.or(self.map(|s| s.smtp_password))
.flatten(),
smtp_from_address,
use_tls,
})
} else {
None
}
} }
} }
impl Merge<DatabaseConfigOpt> for DatabaseConfig { impl Merge<DatabaseConfigOpt> for DatabaseConfig {
fn merge(&mut self, opt: DatabaseConfigOpt) { fn merge(self, opt: DatabaseConfigOpt) -> Self {
overwrite_if_some(&mut self.user, opt.user); DatabaseConfig {
overwrite_if_some(&mut self.password, opt.password); user: opt.user.unwrap_or(self.user),
overwrite_if_some(&mut self.host, opt.host); password: opt.password.unwrap_or(self.password),
overwrite_if_some(&mut self.port, opt.port); host: opt.host.unwrap_or(self.host),
overwrite_if_some(&mut self.database, opt.database); port: opt.port.unwrap_or(self.port),
overwrite_if_some(&mut self.pool_size, opt.pool_size); database: opt.database.unwrap_or(self.database),
pool_size: opt.pool_size.unwrap_or(self.pool_size),
}
} }
} }
impl Merge<FederationConfigOpt> for FederationConfig { impl Merge<FederationConfigOpt> for FederationConfig {
fn merge(&mut self, opt: FederationConfigOpt) { fn merge(self, opt: FederationConfigOpt) -> Self {
overwrite_if_some(&mut self.enabled, opt.enabled); FederationConfig {
overwrite_if_some(&mut self.allowed_instances, opt.allowed_instances); enabled: opt.enabled.unwrap_or(self.enabled),
overwrite_if_some(&mut self.blocked_instances, opt.blocked_instances); allowed_instances: opt.allowed_instances.unwrap_or(self.allowed_instances),
blocked_instances: opt.blocked_instances.unwrap_or(self.blocked_instances),
}
} }
} }
impl Merge<CaptchaConfigOpt> for CaptchaConfig { impl Merge<CaptchaConfigOpt> for CaptchaConfig {
fn merge(&mut self, opt: CaptchaConfigOpt) { fn merge(self, opt: CaptchaConfigOpt) -> Self {
overwrite_if_some(&mut self.enabled, opt.enabled); CaptchaConfig {
overwrite_if_some(&mut self.difficulty, opt.difficulty); enabled: opt.enabled.unwrap_or(self.enabled),
} difficulty: opt.difficulty.unwrap_or(self.difficulty),
}
fn overwrite_if_some<T>(lhs: &mut T, rhs: Option<T>) {
if let Some(x) = rhs {
*lhs = x;
}
}
fn merge_if_some<T, U>(lhs: &mut T, rhs: Option<U>)
where
T: Merge<U>,
{
if let Some(x) = rhs {
lhs.merge(x);
}
}
fn merge_if_some_opt<T, U>(lhs: &mut Option<T>, rhs: Option<U>)
where
T: Merge<U>,
{
if let Some(x) = rhs {
if let Some(y) = lhs {
y.merge(x)
} }
} }
} }
fn merge_structs<T, U>(lhs: T, rhs: Option<U>) -> T
where
T: Merge<U> + std::clone::Clone,
{
if let Some(x) = rhs {
lhs.merge(x)
} else {
lhs.to_owned()
}
}

View file

@ -10,7 +10,7 @@ use crate::{
}; };
use anyhow::{anyhow, Context}; use anyhow::{anyhow, Context};
use deser_hjson::from_str; use deser_hjson::from_str;
use std::{env, fs, io::Error, sync::RwLock}; use std::{env, fs, sync::RwLock};
pub mod defaults; pub mod defaults;
mod environment; mod environment;
@ -39,10 +39,12 @@ impl Settings {
let mut config = Settings::default(); let mut config = Settings::default();
// Read the config file // Read the config file
config.merge(from_str::<SettingsOpt>(&Self::read_config_file()?)?); if let Some(config_file) = &Self::read_config_file() {
config = config.merge(from_str::<SettingsOpt>(config_file)?);
}
// Read env vars // Read env vars
config.merge(parse_from_env()); config = config.merge(parse_from_env());
if config.hostname == Settings::default().hostname { if config.hostname == Settings::default().hostname {
return Err(anyhow!("Hostname variable is not set!").into()); return Err(anyhow!("Hostname variable is not set!").into());
@ -68,8 +70,8 @@ impl Settings {
env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string()) env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string())
} }
pub fn read_config_file() -> Result<String, Error> { pub fn read_config_file() -> Option<String> {
fs::read_to_string(Self::get_config_location()) fs::read_to_string(Self::get_config_location()).ok()
} }
pub fn get_allowed_instances(&self) -> Vec<String> { pub fn get_allowed_instances(&self) -> Vec<String> {
@ -133,7 +135,7 @@ impl Settings {
) )
} }
pub fn save_config_file(data: &str) -> Result<String, Error> { pub fn save_config_file(data: &str) -> Result<String, LemmyError> {
fs::write(CONFIG_FILE, data)?; fs::write(CONFIG_FILE, data)?;
// Reload the new settings // Reload the new settings
@ -144,6 +146,6 @@ impl Settings {
Err(e) => panic!("{}", e), Err(e) => panic!("{}", e),
}; };
Self::read_config_file() Self::read_config_file().ok_or(anyhow!("Failed to read config").into())
} }
} }

View file

@ -39,6 +39,7 @@ services:
lemmy-alpha: lemmy-alpha:
image: lemmy-federation:latest image: lemmy-federation:latest
environment: environment:
- RUST_BACKTRACE=full
- LEMMY_HOSTNAME=lemmy-alpha:8541 - LEMMY_HOSTNAME=lemmy-alpha:8541
- LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_alpha:5432/lemmy - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_alpha:5432/lemmy
- LEMMY_JWT_SECRET=changeme - LEMMY_JWT_SECRET=changeme

View file

@ -8,4 +8,5 @@ for Item in alpha beta gamma delta epsilon ; do
sudo chown -R 991:991 volumes/pictrs_$Item sudo chown -R 991:991 volumes/pictrs_$Item
done done
sudo docker-compose up sudo docker-compose up -d
sudo docker-compose logs -f lemmy-alpha