use crate::operator_cli::types::OperatorConfigFile;
use anyhow::Context;
use bucketwarden_server::RuntimeConfig;
#[derive(Clone, Debug)]
pub struct RuntimeConfigSelection {
pub config: RuntimeConfig,
pub source: &'static str,
pub source_path: Option<String>,
}
const BUCKETWARDEN_CONFIG_ENV: &str = "BUCKETWARDEN_CONFIG";
const CONFIG_SOURCE_DEFAULT: &str = "default";
const CONFIG_SOURCE_ENV: &str = "environment";
const CONFIG_SOURCE_EXPLICIT: &str = "explicit";
pub fn load_runtime_config(path: Option<&str>) -> anyhow::Result<RuntimeConfig> {
Ok(resolve_runtime_config(path)?.config)
}
pub fn load_runtime_config_with_source(
path: Option<&str>,
) -> anyhow::Result<RuntimeConfigSelection> {
resolve_runtime_config(path)
}
pub(crate) fn resolve_runtime_config(path: Option<&str>) -> anyhow::Result<RuntimeConfigSelection> {
let Some(path) = path else {
if let Ok(env_path) = std::env::var(BUCKETWARDEN_CONFIG_ENV) {
let env_path = env_path.trim().to_string();
if !env_path.is_empty() {
return parse_runtime_config_from_path(&env_path, CONFIG_SOURCE_ENV);
}
}
return Ok(RuntimeConfigSelection {
config: RuntimeConfig::development(),
source: CONFIG_SOURCE_DEFAULT,
source_path: None,
});
};
parse_runtime_config_from_path(path, CONFIG_SOURCE_EXPLICIT)
}
pub(crate) fn parse_runtime_config_from_path(
path: &str,
source: &'static str,
) -> anyhow::Result<RuntimeConfigSelection> {
let payload = std::fs::read_to_string(path)
.with_context(|| format!("failed to read runtime config from `{path}`"))?;
let config: OperatorConfigFile = serde_json::from_str(&payload)
.with_context(|| format!("invalid runtime config JSON at `{path}`"))?;
validate_config_fields(&config)?;
Ok(RuntimeConfigSelection {
config: RuntimeConfig {
key_id: config.key_id,
key_material: config.key_material.into_bytes(),
clock_epoch_seconds: config.clock_epoch_seconds,
},
source,
source_path: Some(path.to_string()),
})
}
pub(crate) fn validate_config_fields(config: &OperatorConfigFile) -> anyhow::Result<()> {
if config.key_id.trim().is_empty() {
anyhow::bail!("config key_id must not be empty");
}
if config.key_material.is_empty() {
anyhow::bail!("config key_material must not be empty");
}
Ok(())
}