use local_ip_address::{local_ip, local_ipv6};
use serde::Deserialize;
use std::fs;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::PathBuf;
use std::time::Duration;
use tracing::info;
use validator::Validate;
pub const NAME: &str = "dfdaemon";
pub fn default_dfdaemon_config_path() -> PathBuf {
super::default_config_dir().join("dfdaemon.yaml")
}
pub fn default_dfdaemon_log_dir() -> PathBuf {
super::default_log_dir().join(NAME)
}
pub fn default_dfdaemon_plugin_dir() -> PathBuf {
super::default_plugin_dir().join(NAME)
}
pub fn default_dfdaemon_cache_dir() -> PathBuf {
super::default_cache_dir().join(NAME)
}
pub fn default_dfdaemon_unix_socket_path() -> PathBuf {
super::default_root_dir().join("dfdaemon.sock")
}
pub fn default_dfdaemon_lock_path() -> PathBuf {
super::default_lock_dir().join("dfdaemon.lock")
}
pub fn default_tracing_addr() -> SocketAddr {
SocketAddr::from((Ipv4Addr::LOCALHOST, 14268))
}
pub fn default_scheduler_announce_interval() -> Duration {
Duration::from_secs(30)
}
pub fn default_scheduler_schedule_timeout() -> Duration {
Duration::from_secs(300)
}
pub fn default_dynconfig_refresh_interval() -> Duration {
Duration::from_secs(600)
}
pub fn default_seed_peer_keepalive_interval() -> Duration {
Duration::from_secs(15)
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
IO(#[from] std::io::Error),
#[error(transparent)]
YAML(#[from] serde_yaml::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Host {
pub idc: Option<String>,
pub location: Option<String>,
pub hostname: String,
pub ip: IpAddr,
}
impl Default for Host {
fn default() -> Self {
Host {
idc: None,
location: None,
hostname: hostname::get().unwrap().to_string_lossy().to_string(),
ip: local_ip().unwrap(),
}
}
}
#[derive(Debug, Clone, Default, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Manager {
pub addrs: Vec<SocketAddr>,
}
#[derive(Debug, Clone, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Scheduler {
pub announce_interval: Duration,
pub schedule_timeout: Duration,
pub enable_back_to_source: bool,
}
impl Default for Scheduler {
fn default() -> Self {
Scheduler {
announce_interval: default_scheduler_announce_interval(),
schedule_timeout: default_scheduler_schedule_timeout(),
enable_back_to_source: true,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
pub enum SeedPeerType {
#[serde(rename = "super")]
Super,
#[serde(rename = "strong")]
Strong,
#[serde(rename = "weak")]
Weak,
}
#[derive(Debug, Clone, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct SeedPeer {
pub enable: bool,
#[serde(rename = "type")]
pub kind: SeedPeerType,
pub cluster_id: u32,
pub keepalive_interval: Duration,
}
impl Default for SeedPeer {
fn default() -> Self {
SeedPeer {
enable: false,
kind: SeedPeerType::Super,
cluster_id: 1,
keepalive_interval: default_seed_peer_keepalive_interval(),
}
}
}
#[derive(Debug, Clone, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Dynconfig {
pub refresh_interval: Duration,
}
impl Default for Dynconfig {
fn default() -> Self {
Dynconfig {
refresh_interval: default_dynconfig_refresh_interval(),
}
}
}
#[derive(Debug, Clone, Default, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Downloader {}
#[derive(Debug, Clone, Default, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Uploader {}
#[derive(Debug, Clone, Default, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Storage {}
#[derive(Debug, Clone, Default, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Proxy {
pub enable: bool,
}
#[derive(Debug, Clone, Default, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Security {
pub enable: bool,
}
#[derive(Debug, Clone, Default, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct ObjectStorage {
pub enable: bool,
}
#[derive(Debug, Clone, Default, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Network {
pub enable_ipv6: bool,
}
#[derive(Debug, Clone, Default, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Metrics {
pub enable: bool,
}
#[derive(Debug, Clone, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Tracing {
pub enable: bool,
pub addr: SocketAddr,
}
impl Default for Tracing {
fn default() -> Self {
Tracing {
enable: false,
addr: default_tracing_addr(),
}
}
}
#[derive(Debug, Clone, Validate, Deserialize)]
#[serde(default, rename_all = "camelCase")]
pub struct Config {
pub data_dir: PathBuf,
pub plugin_dir: PathBuf,
pub cache_dir: PathBuf,
pub root_dir: PathBuf,
pub lock_dir: PathBuf,
pub host: Host,
pub manager: Manager,
pub scheduler: Scheduler,
pub seed_peer: SeedPeer,
pub dynconfig: Dynconfig,
pub downloader: Downloader,
pub uploader: Uploader,
pub storage: Storage,
pub proxy: Proxy,
pub security: Security,
pub object_storage: ObjectStorage,
pub metrics: Metrics,
pub tracing: Tracing,
pub network: Network,
}
impl Default for Config {
fn default() -> Self {
Config {
data_dir: super::default_data_dir(),
plugin_dir: default_dfdaemon_plugin_dir(),
cache_dir: default_dfdaemon_cache_dir(),
root_dir: super::default_root_dir(),
lock_dir: super::default_lock_dir(),
host: Host::default(),
manager: Manager::default(),
scheduler: Scheduler::default(),
seed_peer: SeedPeer::default(),
dynconfig: Dynconfig::default(),
downloader: Downloader::default(),
uploader: Uploader::default(),
storage: Storage::default(),
proxy: Proxy::default(),
security: Security::default(),
object_storage: ObjectStorage::default(),
network: Network::default(),
metrics: Metrics::default(),
tracing: Tracing::default(),
}
}
}
impl Config {
pub fn load(path: &PathBuf) -> Result<Config> {
if path.exists() {
let content = fs::read_to_string(path)?;
let mut config: Config = serde_yaml::from_str(&content)?;
info!("load config from {}", path.display());
config.convert();
Ok(config)
} else {
info!(
"config file {} not found, use default config",
path.display()
);
Ok(Self::default())
}
}
fn convert(&mut self) {
if self.network.enable_ipv6 {
self.host.ip = local_ipv6().unwrap()
}
}
}