|
|
@@ -3,23 +3,26 @@ use crate::{
|
|
|
Config,
|
|
|
};
|
|
|
use anyhow::{Context, Result};
|
|
|
-use notify::{EventKind, RecursiveMode, Watcher};
|
|
|
-use std::path::PathBuf;
|
|
|
+use notify::{event::ModifyKind, EventKind, RecursiveMode, Watcher};
|
|
|
+use std::{
|
|
|
+ collections::HashMap,
|
|
|
+ path::{Path, PathBuf},
|
|
|
+};
|
|
|
use tokio::sync::{broadcast, mpsc};
|
|
|
use tracing::{error, info, instrument};
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
pub enum ConfigChangeEvent {
|
|
|
- General(Config), // Trigger a full restart
|
|
|
+ General(Box<Config>), // Trigger a full restart
|
|
|
ServiceChange(ServiceChangeEvent),
|
|
|
}
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
pub enum ServiceChangeEvent {
|
|
|
- AddClientService(ClientServiceConfig),
|
|
|
- DeleteClientService(ClientServiceConfig),
|
|
|
- AddServerService(ServerServiceConfig),
|
|
|
- DeleteServerService(ServerServiceConfig),
|
|
|
+ ClientAdd(ClientServiceConfig),
|
|
|
+ ClientDelete(String),
|
|
|
+ ServerAdd(ServerServiceConfig),
|
|
|
+ ServerDelete(String),
|
|
|
}
|
|
|
|
|
|
pub struct ConfigWatcherHandle {
|
|
|
@@ -27,7 +30,7 @@ pub struct ConfigWatcherHandle {
|
|
|
}
|
|
|
|
|
|
impl ConfigWatcherHandle {
|
|
|
- pub async fn new(path: &PathBuf, shutdown_rx: broadcast::Receiver<bool>) -> Result<Self> {
|
|
|
+ pub async fn new(path: &Path, shutdown_rx: broadcast::Receiver<bool>) -> Result<Self> {
|
|
|
let (event_tx, event_rx) = mpsc::channel(16);
|
|
|
|
|
|
let origin_cfg = Config::from_file(path).await?;
|
|
|
@@ -43,7 +46,7 @@ impl ConfigWatcherHandle {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#[instrument(skip(shutdown_rx, cfg_event_tx))]
|
|
|
+#[instrument(skip(shutdown_rx, cfg_event_tx, old))]
|
|
|
async fn config_watcher(
|
|
|
path: PathBuf,
|
|
|
mut shutdown_rx: broadcast::Receiver<bool>,
|
|
|
@@ -61,7 +64,7 @@ async fn config_watcher(
|
|
|
|
|
|
// Initial start
|
|
|
cfg_event_tx
|
|
|
- .send(ConfigChangeEvent::General(old.clone()))
|
|
|
+ .send(ConfigChangeEvent::General(Box::new(old.clone())))
|
|
|
.await
|
|
|
.unwrap();
|
|
|
|
|
|
@@ -73,9 +76,12 @@ async fn config_watcher(
|
|
|
e = fevent_rx.recv() => {
|
|
|
match e {
|
|
|
Some(e) => {
|
|
|
- match e.kind {
|
|
|
- EventKind::Modify(_) => {
|
|
|
- info!("Configuration modify event is detected");
|
|
|
+ if let EventKind::Modify(kind) = e.kind {
|
|
|
+ match kind {
|
|
|
+ ModifyKind::Data(_) => (),
|
|
|
+ _ => continue
|
|
|
+ }
|
|
|
+ info!("Rescan the configuration");
|
|
|
let new = match Config::from_file(&path).await.with_context(|| "The changed configuration is invalid. Ignored") {
|
|
|
Ok(v) => v,
|
|
|
Err(e) => {
|
|
|
@@ -90,9 +96,7 @@ async fn config_watcher(
|
|
|
}
|
|
|
|
|
|
old = new;
|
|
|
- },
|
|
|
- _ => (), // Just ignore other events
|
|
|
- }
|
|
|
+ }
|
|
|
},
|
|
|
None => break
|
|
|
}
|
|
|
@@ -109,11 +113,71 @@ async fn config_watcher(
|
|
|
fn calculate_event(old: &Config, new: &Config) -> Vec<ConfigChangeEvent> {
|
|
|
let mut ret = Vec::new();
|
|
|
|
|
|
- if old == new {
|
|
|
- return ret;
|
|
|
+ if old != new {
|
|
|
+ if old.server.is_some() && new.server.is_some() {
|
|
|
+ let mut e: Vec<ConfigChangeEvent> = calculate_service_delete_event(
|
|
|
+ &old.server.as_ref().unwrap().services,
|
|
|
+ &new.server.as_ref().unwrap().services,
|
|
|
+ )
|
|
|
+ .into_iter()
|
|
|
+ .map(|x| ConfigChangeEvent::ServiceChange(ServiceChangeEvent::ServerDelete(x)))
|
|
|
+ .collect();
|
|
|
+ ret.append(&mut e);
|
|
|
+
|
|
|
+ let mut e: Vec<ConfigChangeEvent> = calculate_service_add_event(
|
|
|
+ &old.server.as_ref().unwrap().services,
|
|
|
+ &new.server.as_ref().unwrap().services,
|
|
|
+ )
|
|
|
+ .into_iter()
|
|
|
+ .map(|x| ConfigChangeEvent::ServiceChange(ServiceChangeEvent::ServerAdd(x)))
|
|
|
+ .collect();
|
|
|
+
|
|
|
+ ret.append(&mut e);
|
|
|
+ } else if old.client.is_some() && new.client.is_some() {
|
|
|
+ let mut e: Vec<ConfigChangeEvent> = calculate_service_delete_event(
|
|
|
+ &old.client.as_ref().unwrap().services,
|
|
|
+ &new.client.as_ref().unwrap().services,
|
|
|
+ )
|
|
|
+ .into_iter()
|
|
|
+ .map(|x| ConfigChangeEvent::ServiceChange(ServiceChangeEvent::ClientDelete(x)))
|
|
|
+ .collect();
|
|
|
+ ret.append(&mut e);
|
|
|
+
|
|
|
+ let mut e: Vec<ConfigChangeEvent> = calculate_service_add_event(
|
|
|
+ &old.client.as_ref().unwrap().services,
|
|
|
+ &new.client.as_ref().unwrap().services,
|
|
|
+ )
|
|
|
+ .into_iter()
|
|
|
+ .map(|x| ConfigChangeEvent::ServiceChange(ServiceChangeEvent::ClientAdd(x)))
|
|
|
+ .collect();
|
|
|
+
|
|
|
+ ret.append(&mut e);
|
|
|
+ } else {
|
|
|
+ ret.push(ConfigChangeEvent::General(Box::new(new.clone())));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- ret.push(ConfigChangeEvent::General(new.to_owned()));
|
|
|
-
|
|
|
ret
|
|
|
}
|
|
|
+
|
|
|
+fn calculate_service_delete_event<T: PartialEq>(
|
|
|
+ old_services: &HashMap<String, T>,
|
|
|
+ new_services: &HashMap<String, T>,
|
|
|
+) -> Vec<String> {
|
|
|
+ old_services
|
|
|
+ .keys()
|
|
|
+ .filter(|&name| old_services.get(name) != new_services.get(name))
|
|
|
+ .map(|x| x.to_owned())
|
|
|
+ .collect()
|
|
|
+}
|
|
|
+
|
|
|
+fn calculate_service_add_event<T: PartialEq + Clone>(
|
|
|
+ old_services: &HashMap<String, T>,
|
|
|
+ new_services: &HashMap<String, T>,
|
|
|
+) -> Vec<T> {
|
|
|
+ new_services
|
|
|
+ .iter()
|
|
|
+ .filter(|(name, _)| old_services.get(*name) != new_services.get(*name))
|
|
|
+ .map(|(_, c)| c.clone())
|
|
|
+ .collect()
|
|
|
+}
|