use crate::CoreError;
use directories::ProjectDirs;
use quic_p2p::Config as QuicP2pConfig;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
#[cfg(test)]
use std::{fs, path::PathBuf};
use std::{
fs::File,
io::{self, BufReader},
};
const CONFIG_DIR_QUALIFIER: &str = "net";
const CONFIG_DIR_ORGANISATION: &str = "MaidSafe";
const CONFIG_DIR_APPLICATION: &str = "safe_core";
const CONFIG_FILE: &str = "safe_core.config";
const VAULT_CONFIG_DIR_APPLICATION: &str = "safe_vault";
const VAULT_CONNECTION_INFO_FILE: &str = "vault_connection_info.config";
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Config {
pub quic_p2p: QuicP2pConfig,
pub dev: Option<DevConfig>,
}
impl Config {
pub fn new() -> Self {
let quic_p2p = Self::read_qp2p_from_file().unwrap_or_default();
Self {
quic_p2p,
dev: None,
}
}
fn read_qp2p_from_file() -> Result<QuicP2pConfig, CoreError> {
let mut config: QuicP2pConfig = {
match read_config_file(dirs()?, CONFIG_FILE) {
Err(CoreError::IoError(ref err)) if err.kind() == io::ErrorKind::NotFound => {
QuicP2pConfig {
our_type: quic_p2p::OurType::Client,
..Default::default()
}
}
result => result?,
}
};
if let Ok(node_info) = read_config_file(vault_dirs()?, VAULT_CONNECTION_INFO_FILE) {
let _ = config.hard_coded_contacts.insert(node_info);
}
Ok(config)
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct DevConfig {
pub mock_unlimited_coins: bool,
pub mock_in_memory_storage: bool,
pub mock_vault_path: Option<String>,
}
pub fn get_config() -> Config {
Config::new()
}
fn dirs() -> Result<ProjectDirs, CoreError> {
ProjectDirs::from(
CONFIG_DIR_QUALIFIER,
CONFIG_DIR_ORGANISATION,
CONFIG_DIR_APPLICATION,
)
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "Home directory not found").into())
}
fn vault_dirs() -> Result<ProjectDirs, CoreError> {
ProjectDirs::from(
CONFIG_DIR_QUALIFIER,
CONFIG_DIR_ORGANISATION,
VAULT_CONFIG_DIR_APPLICATION,
)
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "Home directory not found").into())
}
fn read_config_file<T>(dirs: ProjectDirs, file: &str) -> Result<T, CoreError>
where
T: DeserializeOwned,
{
let path = dirs.config_dir().join(file);
let file = match File::open(&path) {
Ok(file) => {
trace!("Reading: {}", path.display());
file
}
Err(error) => {
trace!("Not available: {}", path.display());
return Err(error.into());
}
};
let reader = BufReader::new(file);
serde_json::from_reader(reader).map_err(|err| {
info!("Could not parse: {} ({:?})", err, err);
err.into()
})
}
#[cfg(test)]
#[allow(unused)]
pub fn write_config_file(config: &Config) -> Result<PathBuf, CoreError> {
let dirs = dirs()?;
let dir = dirs.config_dir();
fs::create_dir_all(dir)?;
let path = dir.join(CONFIG_FILE);
dbg!(&path);
let mut file = File::create(&path)?;
serde_json::to_writer_pretty(&mut file, config)?;
file.sync_all()?;
Ok(path)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[ignore]
fn write_default_config_file() {
let config = Config::default();
unwrap!(write_config_file(&config));
}
}