use std::path::PathBuf;
use config::{Config, ConfigError, File};
use dfir_rs::futures::future::ready;
use dfir_rs::futures::{Stream, StreamExt};
use notify::{Event, EventHandler, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc::UnboundedSender;
use tracing::trace;
#[derive(Debug, Deserialize, Serialize)]
pub struct ServerSettings {
pub seed_nodes: Vec<SeedNodeSettings>,
}
const CONFIG_ROOT: &str = "config";
const STATIC_CONFIG_PATH: &str = "static";
const DYNAMIC_CONFIG_PATH: &str = "dynamic";
fn static_config_path(subpath: &str) -> PathBuf {
PathBuf::from(CONFIG_ROOT)
.join(STATIC_CONFIG_PATH)
.join(subpath)
}
fn dynamic_config_path(subpath: &str) -> PathBuf {
PathBuf::from(CONFIG_ROOT)
.join(DYNAMIC_CONFIG_PATH)
.join(subpath)
}
impl ServerSettings {
pub fn new() -> Result<Self, ConfigError> {
let run_mode = std::env::var("RUN_MODE").unwrap_or_else(|_| "development".into());
let settings = Config::builder()
.add_source(File::from(static_config_path("default.toml")).required(false))
.add_source(File::from(static_config_path(&run_mode)).required(false))
.add_source(File::from(static_config_path("local")).required(false))
.add_source(File::from(dynamic_config_path("dynamic.toml")).required(false))
.build()?;
settings.try_deserialize()
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash)]
pub struct SeedNodeSettings {
pub id: String,
pub address: String,
}
pub fn setup_settings_watch() -> (
RecommendedWatcher,
ServerSettings,
impl Stream<Item = ServerSettings>,
) {
let (tx, rx) = dfir_rs::util::unbounded_channel();
let mut watcher = notify::RecommendedWatcher::new(
UnboundedSenderEventHandler::new(tx),
notify::Config::default(),
)
.unwrap();
watcher
.watch(&PathBuf::from(CONFIG_ROOT), RecursiveMode::Recursive)
.unwrap();
let initial_settings = ServerSettings::new().unwrap();
let change_stream = rx
.map(Result::unwrap)
.map(|event| {
trace!("Event: {:?}", event);
match event.kind {
EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_) => {
Some(ServerSettings::new().unwrap())
}
_ => {
trace!("Unhandled event: {:?}", event);
None
}
}
})
.filter_map(ready);
(watcher, initial_settings, change_stream)
}
struct UnboundedSenderEventHandler {
tx: UnboundedSender<notify::Result<Event>>,
}
impl UnboundedSenderEventHandler {
fn new(tx: UnboundedSender<notify::Result<Event>>) -> Self {
Self { tx }
}
}
impl EventHandler for UnboundedSenderEventHandler {
fn handle_event(&mut self, event: notify::Result<Event>) {
self.tx.send(event).unwrap();
}
}