#[cfg(feature = "secret")]
use crate::encrypt_utils::Encrypter;
use crate::error::ConfigResult;
#[cfg(feature = "persist")]
use serde::{de::DeserializeOwned, Serialize};
#[cfg(feature = "persist")]
use std::path::PathBuf;
pub trait Source: Default {
fn load() -> ConfigResult<Self>
where
Self: Sized;
fn save(&self) -> ConfigResult<()>;
fn load_or_default() -> Self
where
Self: Sized + Default,
{
Self::load().unwrap_or_default()
}
}
pub trait NormalSource: Source {}
#[cfg(feature = "persist")]
pub trait PersistSource: Source + Serialize + DeserializeOwned {
#[cfg(not(feature = "default_config_dir"))]
const PATH: &'static str;
#[cfg(feature = "default_config_dir")]
const NAME: &'static str;
fn path() -> PathBuf {
#[cfg(not(feature = "default_config_dir"))]
{
PathBuf::from(Self::PATH)
}
#[cfg(feature = "default_config_dir")]
{
dirs::config_dir()
.expect("Default config dir unknown in your OS.")
.join(Self::NAME)
}
}
fn load() -> ConfigResult<Self> {
let path = Self::path();
let file = std::fs::File::open(path)?;
Ok(serde_json::from_reader(file)?)
}
fn save(&self) -> ConfigResult<()> {
let path = Self::path();
let parent = path.parent().unwrap();
std::fs::create_dir_all(parent).unwrap();
let file = std::fs::File::create(path).unwrap();
serde_json::to_writer(file, self)?;
Ok(())
}
}
#[cfg(feature = "secret")]
pub trait SecretSource: Source + Serialize + DeserializeOwned {
#[cfg(not(feature = "default_config_dir"))]
const PATH: &'static str;
#[cfg(feature = "default_config_dir")]
const NAME: &'static str;
const KEYRING_ENTRY: &'static str;
fn path() -> PathBuf {
#[cfg(not(feature = "default_config_dir"))]
{
PathBuf::from(Self::PATH)
}
#[cfg(feature = "default_config_dir")]
{
dirs::config_dir()
.expect("Default config dir unknown in your OS.")
.join(Self::NAME)
}
}
fn load() -> ConfigResult<Self> {
let path = Self::path();
let encrypter = Encrypter::new(Self::KEYRING_ENTRY)?;
let file = std::fs::File::open(path)?;
let encrypted: Vec<u8> = std::io::Read::bytes(file).collect::<Result<_, _>>()?;
encrypter.decrypt(&encrypted)
}
fn save(&self) -> ConfigResult<()> {
use std::io::Write as _;
let path = Self::path();
let parent = path.parent().unwrap();
std::fs::create_dir_all(parent).unwrap();
let encrypter = Encrypter::new(Self::KEYRING_ENTRY)?;
let encrypted = encrypter.encrypt(self)?;
let mut file = std::fs::File::create(path).unwrap();
file.write_all(&encrypted)?;
file.flush()?;
Ok(())
}
}