use std::{collections::HashMap, fmt, path::Path};
use ohlcv::{database::DbType, Coin, Currency, Exchange};
use serde::Deserialize;
use tracing::{info, instrument};
use crate::Error;
pub const CONFIG_FILE: &str = concat!(env!("CARGO_PKG_NAME"), ".toml",);
pub const CONFIG_PATHS: [&str; 2] = [".", "/etc/ohlcv"];
const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
pub type ExchangeMap = HashMap<Exchange, String>;
#[derive(Debug, Deserialize)]
#[allow(clippy::module_name_repetitions, dead_code)]
pub struct CoinConfig {
symbol: String,
name: String,
currency: Currency,
pub exchanges: ExchangeMap,
}
impl CoinConfig {
#[must_use]
pub fn as_coin(&self) -> ohlcv::Coin {
Coin::new(self.symbol.clone(), self.name.clone(), self.currency)
}
}
#[derive(Debug, Deserialize)]
pub struct Config {
user_agent: Option<Box<str>>,
pub database: DbType,
pub coins: Vec<CoinConfig>,
}
impl Config {
#[instrument]
pub fn load(path: Option<impl AsRef<Path> + fmt::Debug>) -> Result<Self, Error> {
let path = path
.map(|p| p.as_ref().to_path_buf())
.or_else(|| {
CONFIG_PATHS
.iter()
.map(|p| Path::new(p).join(CONFIG_FILE))
.find(|p| p.exists())
})
.ok_or_else(|| Error::ConfigFile)?;
info!("Loading configuration from {:?}", path);
let source = std::fs::read_to_string(path)?;
toml::from_str(&source).map_err(Error::ConfigFormat)
}
#[must_use]
#[inline]
#[instrument(skip(self))]
pub fn user_agent(&self) -> &str {
self.user_agent.as_deref().unwrap_or(USER_AGENT)
}
}