findpenguins-feed/src/config.rs

80 lines
2.8 KiB
Rust

use std::path::PathBuf;
use config::{Config, ConfigError, Environment};
use directories::ProjectDirs;
use serde::Deserialize;
use thiserror::Error;
use tracing::debug;
#[derive(Error, Debug)]
pub enum AppConfigError {
#[error("No valid home directory found.")]
HomePathError,
#[error("Configuration error.")]
ConfigError(#[from] ConfigError),
}
fn default_server_address() -> String {
String::from("[::1]:3000")
}
fn default_feeds() -> Vec<String> {
Vec::new()
}
#[derive(Clone, Debug, Default, Deserialize)]
pub struct PenguinConfig {
#[serde(default = "default_server_address")]
pub server_address: String,
#[serde(default = "default_feeds")]
pub feeds: Vec<String>,
}
impl PenguinConfig {
/// Find the correct project directory for the respective operating system.
fn get_project_dirs() -> Result<ProjectDirs, AppConfigError> {
let project_dirs = ProjectDirs::from("ch", "vanwa", "findpenguins-feed")
.ok_or(AppConfigError::HomePathError)?;
Ok(project_dirs)
}
/// Find the correct configuration file for the respective operating system.
/// - linux: `$XDG_CONFIG_HOME/stray/config.toml` or `$HOME/.config/stray/config.toml`
/// - macOS: `$HOME/Library/Preferences/ch.fhnw.stray/config.toml`
/// - windows: `{FOLDERID_RoamingAppData}/stray/config/config.toml`
fn config_path() -> Result<PathBuf, AppConfigError> {
let project_dirs = Self::get_project_dirs()?;
let config_path = project_dirs.config_dir();
let config_file = config_path.join("config.toml");
Ok(config_file)
}
/// Read the server configuration.
/// See [config_path](struct.AppConfig.html#method.config_path) for the different configuration file paths.
/// Everything in the config file can be overridden at runtime by setting the respective ENV variables.
/// Use `__` (double underscore) as a separator between hierarchies.
/// For example `WOWEB__INITIAL_REMOTES="http://[::1]:3002,http://[::1]:3003"`
/// This is necessary for configuration keys to have single underscores.
pub fn read() -> Result<Self, AppConfigError> {
let mut config_builder = Config::builder();
if let Ok(config_path) = Self::config_path() {
debug!("trying config file at {:#?}...", config_path);
config_builder =
config_builder.add_source(config::File::from(config_path).required(false));
}
debug!("merging settings from environment variables...");
config_builder = config_builder.add_source(
Environment::with_prefix("findpenguins_feed")
.separator("__")
.list_separator(",")
.with_list_parse_key("feeds")
.try_parsing(true),
);
Ok(config_builder.build()?.try_deserialize()?)
}
}