Compare commits

...

3 Commits

Author SHA1 Message Date
771b8e5ce4 Initialize config defaults in separate function
All checks were successful
Push Workflows / rustfmt (push) Successful in 6s
Push Workflows / tailwind-build (push) Successful in 6s
Push Workflows / docs (push) Successful in 20s
Push Workflows / test (push) Successful in 24s
Push Workflows / clippy (push) Successful in 18s
Push Workflows / build (push) Successful in 47s
Push Workflows / nix-build (push) Successful in 5m16s
2026-07-19 10:06:33 -04:00
b15b8b2ae1 Move load_config to Config::from_env 2026-07-19 10:00:07 -04:00
a0931eb420 Allow equality comparison of Error 2026-07-19 09:55:08 -04:00
3 changed files with 38 additions and 30 deletions

View File

@@ -1,6 +1,7 @@
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::PathBuf;
use config::{ConfigBuilder, ConfigError, builder::DefaultState};
use serde::Deserialize;
/// Enable secure cookies by default only in release mode
@@ -201,32 +202,39 @@ pub struct Config {
pub server: ServerConfig,
}
/// Parse configuration from the expected files and environment variables
pub fn load_config() -> Result<Config, config::ConfigError> {
use config::{Environment, File};
impl Config {
/// Parse configuration from the expected files and environment variables
pub fn from_env() -> Result<Self, ConfigError> {
use config::{Environment, File};
let pkg_name = env!("CARGO_PKG_NAME");
let pkg_name = env!("CARGO_PKG_NAME");
config::Config::builder()
.set_default(
"server.port",
dioxus::cli_config::server_port().unwrap_or(8080),
)?
.set_default(
"server.host",
dioxus::cli_config::server_ip()
.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED))
.to_string(),
)?
.set_default("auth.open_signup", false)?
.set_default("auth.cookies_secure", DEFAULT_COOKIES_SECURE)?
.set_default("server.public_path", default_public_dir())?
.add_source(File::with_name(&format!("/etc/{pkg_name}/config")).required(false))
.add_source(File::with_name(&format!("/etc/{pkg_name}")).required(false))
.add_source(File::with_name("config").required(false))
.add_source(Environment::with_prefix(pkg_name).separator("_"))
.build()?
.try_deserialize()
Self::defaults()?
.add_source(File::with_name(&format!("/etc/{pkg_name}/config")).required(false))
.add_source(File::with_name(&format!("/etc/{pkg_name}")).required(false))
.add_source(File::with_name("config").required(false))
.add_source(Environment::with_prefix(pkg_name).separator("_"))
.build()?
.try_deserialize()
}
/// Generate a `config::ConfigBuilder` from default values
fn defaults() -> Result<ConfigBuilder<DefaultState>, ConfigError> {
config::Config::builder()
.set_default(
"server.port",
dioxus::cli_config::server_port().unwrap_or(8080),
)?
.set_default(
"server.host",
dioxus::cli_config::server_ip()
.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED))
.to_string(),
)?
.set_default("auth.open_signup", false)?
.set_default("auth.cookies_secure", DEFAULT_COOKIES_SECURE)?
.set_default("server.public_path", default_public_dir())
}
}
/// Provide a sane default for the public path, using the same sources as Dioxus does internally.

View File

@@ -10,7 +10,7 @@ use tower_http::services::ServeFile;
use crate::App;
use crate::app::LOGO_ICO;
use crate::server::{
auth::build_auth_layer, config, database, key_val_store,
auth::build_auth_layer, config::Config, database, key_val_store,
require_auth_mw::require_auth_middleware,
};
use crate::util::error::{Contextualize, Error, ErrorType, Result};
@@ -21,7 +21,7 @@ pub async fn main() -> Result<std::convert::Infallible> {
}
tracing::debug!("Loading configuration...");
let config = config::load_config()
let config = Config::from_env()
.map_err(|e| Error::message_here(e.to_string()))
.err_context("Failed to load config")?;

View File

@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
/// A location in the source code
/// A thin wrapper over `std::panic::Location`, which isn't `Serialize` or `Deserialize`
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ErrorLocation {
file: String,
line: u32,
@@ -59,7 +59,7 @@ fn rand_modal_id() -> String {
format!("err-modal-{random_str}")
}
#[derive(Debug, Clone, Deserialize, Serialize, thiserror::Error)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, thiserror::Error)]
pub struct Error {
#[source]
/// The error type and data
@@ -307,7 +307,7 @@ impl<T, E: Into<Error>> Contextualize<Result<T>> for E {
}
}
#[derive(Debug, Clone, thiserror::Error, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, thiserror::Error, Deserialize, Serialize)]
pub enum ErrorType {
#[error("Authentication error: {0}")]
Auth(AuthError),
@@ -365,7 +365,7 @@ impl From<fred::error::Error> for Error {
}
}
#[derive(Debug, Clone, thiserror::Error, Deserialize, Serialize)]
#[derive(Debug, Clone, PartialEq, thiserror::Error, Deserialize, Serialize)]
pub enum AuthError {
#[error("Invalid credentials")]
InvalidCredentials,