luci/src/config.rs

113 lines
3.0 KiB
Rust

use std::io::ErrorKind;
use std::path::{Path, PathBuf};
use serde::Deserialize;
use tracing::{debug, info};
use url::Url;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Unable to read configuration file: {0}")]
Io(#[from] std::io::Error),
#[error("Failed to parse configuration file: {0}")]
Toml(#[from] toml::de::Error),
}
#[derive(Debug, Deserialize)]
pub struct EtcdConfig {
#[serde(default = "default_etcd_hosts")]
pub hosts: Vec<Url>,
pub client_cert: Option<PathBuf>,
pub client_key: Option<PathBuf>,
pub ca_cert: Option<PathBuf>,
}
#[derive(Debug, Deserialize)]
pub struct Configuration {
#[serde(default = "default_namespace")]
pub namespace: String,
#[serde(default)]
pub path_prefix: PathBuf,
pub etcd: EtcdConfig,
}
impl Default for EtcdConfig {
fn default() -> Self {
Self {
hosts: default_etcd_hosts(),
client_cert: None,
client_key: None,
ca_cert: None,
}
}
}
impl Default for Configuration {
fn default() -> Self {
Self {
namespace: default_namespace(),
path_prefix: Default::default(),
etcd: Default::default(),
}
}
}
impl Configuration {
pub fn load(path: Option<impl AsRef<Path>>) -> Result<Self, Error> {
let path = path
.map(|p| p.as_ref().into())
.unwrap_or_else(Self::default_path);
debug!("Loading configuration from {}", path.display());
let config = match std::fs::read_to_string(&path) {
Ok(d) => toml::from_str(&d)?,
Err(e) if e.kind() == ErrorKind::NotFound => {
debug!("{}: {}", path.display(), e);
Default::default()
}
Err(e) => return Err(e.into()),
};
match std::env::var("DUMP_CONFIG") {
Ok(s) if s == "1" => info!("{:?}", config),
Ok(_) | Err(_) => (),
};
Ok(config)
}
pub fn default_path() -> PathBuf {
match std::env::var_os(format!(
"{}_CONFIG",
env!("CARGO_PKG_NAME").to_uppercase()
)) {
Some(v) => PathBuf::from(v),
None => match std::env::var_os("XDG_CONFIG_HOME") {
Some(v) => {
let mut p = PathBuf::from(v);
p.push(env!("CARGO_PKG_NAME"));
p.push("config.toml");
p
}
None => match std::env::var_os("HOME") {
Some(v) => {
let mut p = PathBuf::from(v);
p.push(".config");
p.push(env!("CARGO_PKG_NAME"));
p.push("config.toml");
p
}
None => PathBuf::from("config.toml"),
},
},
}
}
}
fn default_namespace() -> String {
env!("CARGO_PKG_NAME").into()
}
fn default_etcd_hosts() -> Vec<Url> {
vec![Url::parse("http://localhost:2379").unwrap()]
}