use log::{info, warn};
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, default::Default, fs, path::Path};
use crate::error::AetherError;
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Default)]
#[serde(default)]
pub struct Config {
pub aether: AetherConfig,
pub handshake: HandshakeConfig,
pub link: LinkConfig,
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
#[serde(default)]
pub struct AetherConfig {
pub server_retry_delay: u64,
pub server_poll_time: u64,
pub handshake_retry_delay: u64,
pub connection_check_delay: u64,
pub delta_time: u64,
pub poll_time_us: u64,
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
#[serde(default)]
pub struct HandshakeConfig {
pub peer_poll_time: u64,
pub handshake_timeout: u64,
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
#[serde(default)]
pub struct LinkConfig {
pub window_size: u16,
pub ack_wait_time: u64,
pub poll_time_us: u64,
pub timeout: u64,
pub retry_delay: u64,
pub ack_only_time: u64,
pub max_retries: i16,
}
impl Config {
pub fn from_file(file_path: &Path) -> Result<Config, AetherError> {
match fs::read_to_string(file_path) {
Ok(data) => match Config::try_from(data) {
Ok(config) => Ok(config),
Err(err) => Err(AetherError::YamlParse(err)),
},
Err(err) => Err(AetherError::FileRead(err)),
}
}
pub fn get_config() -> Result<Config, AetherError> {
match home::home_dir() {
Some(mut path_buf) => {
path_buf.push(".config");
path_buf.push("aether");
path_buf.push("config.yaml");
let path = path_buf.as_path();
info!(
"Reading configuration from {}",
path.to_str().unwrap_or("Cannot parse path")
);
match Config::from_file(path) {
Ok(config) => Ok(config),
Err(err) => match err {
AetherError::FileRead(file_err) => {
warn!("{:?}", file_err);
Ok(Config::default())
}
_ => Err(err),
},
}
}
None => Ok(Config::default()),
}
}
}
impl TryFrom<String> for Config {
type Error = serde_yaml::Error;
fn try_from(string: String) -> Result<Self, Self::Error> {
serde_yaml::from_str(&string)
}
}
impl TryFrom<Config> for String {
type Error = serde_yaml::Error;
fn try_from(value: Config) -> Result<Self, Self::Error> {
serde_yaml::to_string(&value)
}
}
impl Default for AetherConfig {
fn default() -> Self {
Self {
server_retry_delay: 1_000,
server_poll_time: 1_000,
handshake_retry_delay: 1_500,
connection_check_delay: 1_000,
delta_time: 1000,
poll_time_us: 100,
}
}
}
impl Default for HandshakeConfig {
fn default() -> Self {
Self {
peer_poll_time: 100,
handshake_timeout: 2_500,
}
}
}
impl Default for LinkConfig {
fn default() -> Self {
Self {
window_size: 20,
ack_wait_time: 1_000,
poll_time_us: 100,
timeout: 10_000,
retry_delay: 100,
ack_only_time: 50,
max_retries: 10,
}
}
}
#[cfg(test)]
mod tests {
use crate::config::Config;
use std::{convert::TryFrom, fs, path::Path};
#[test]
fn read_test() {
let default = Config::default();
let path = "./tmp/config.yaml";
fs::create_dir_all("./tmp").unwrap();
fs::write(path, String::try_from(default).unwrap()).unwrap();
let config = Config::from_file(Path::new(path)).unwrap();
assert_eq!(config, default);
}
}