use snafu::OptionExt;
use std::collections::HashMap;
use crate::{
encrypt_utils::Encrypter, CollectFailed, ConfigNotFound, ConfigResult, PersistSource,
SecretSource, Source,
};
type ConfigKey = String;
type ConfigValue = Vec<u8>;
type ConfigKV = (ConfigKey, ConfigValue);
#[derive(Debug)]
pub struct Config {
inner: HashMap<ConfigKey, ConfigValue>,
encrypter: Encrypter,
}
impl Config {
pub fn new(secret_name: impl AsRef<str>) -> Self {
Self {
inner: HashMap::new(),
encrypter: Encrypter::new(secret_name).unwrap(),
}
}
pub fn get<K, R>(&self, key: K) -> ConfigResult<R>
where
K: AsRef<str>,
R: serde::de::DeserializeOwned,
{
let serded = self.inner.get(key.as_ref()).context(ConfigNotFound {
key: key.as_ref().to_owned(),
})?;
Ok(serde_json::from_slice(serded).unwrap())
}
pub fn add_source(&mut self, source: impl Source) -> ConfigResult<()> {
let patch = source
.collect()
.map_err(|_| CollectFailed.build())?
.into_iter()
.map(|(k, v)| (k, serde_json::to_vec(&v).unwrap()));
self.inner.extend(patch);
Ok(())
}
pub fn add_persist_source(&mut self, source: impl PersistSource) -> ConfigResult<()> {
let patch = source.collect();
self.inner.extend(patch);
Ok(())
}
pub fn add_secret_source(&mut self, source: impl SecretSource) -> ConfigResult<()> {
let patch = source.collect(&self.encrypter);
self.inner.extend(patch);
Ok(())
}
}
type PatchFunc = Box<dyn FnOnce() -> ConfigResult<ConfigKV>>;
pub struct ConfigPatch {
func: PatchFunc,
}
impl ConfigPatch {
pub(crate) fn new(func: PatchFunc) -> Self {
Self { func }
}
pub fn apply(self, config: &mut Config) -> ConfigResult<()> {
let func = self.func;
let (k, v) = func()?;
config.inner.insert(k, v);
Ok(())
}
}
type Func = Box<dyn FnOnce(&Encrypter) -> ConfigResult<ConfigKV>>;
pub struct SecretConfigPatch {
func: Func,
}
impl SecretConfigPatch {
pub(crate) fn new(func: Func) -> Self {
Self { func }
}
pub fn apply(self, config: &mut Config) -> ConfigResult<()> {
let func = self.func;
let (k, v) = func(&config.encrypter)?;
config.inner.insert(k, v);
Ok(())
}
}