small refactoring to reduce duplicaiton of config reloading

This commit is contained in:
trinity-1686a 2022-08-27 12:44:11 +02:00
parent 748d5aea48
commit 8510ba534d
2 changed files with 44 additions and 42 deletions

View File

@ -171,9 +171,9 @@ pub mod exit;
#[cfg(feature = "experimental-api")]
pub mod process;
#[cfg(feature = "experimental-api")]
pub mod socks;
pub mod reload_cfg;
#[cfg(feature = "experimental-api")]
pub mod watch_cfg;
pub mod socks;
#[cfg(all(not(feature = "experimental-api"), feature = "dns-proxy"))]
mod dns;
@ -182,9 +182,9 @@ mod exit;
#[cfg(not(feature = "experimental-api"))]
mod process;
#[cfg(not(feature = "experimental-api"))]
mod socks;
mod reload_cfg;
#[cfg(not(feature = "experimental-api"))]
mod watch_cfg;
mod socks;
use std::fmt::Write;
@ -262,7 +262,7 @@ async fn run<R: Runtime>(
.config(client_config)
.bootstrap_behavior(OnDemand);
let client = client_builder.create_unbootstrapped()?;
watch_cfg::watch_for_config_changes(config_sources, arti_config, client.clone())?;
reload_cfg::watch_for_config_changes(config_sources, arti_config, client.clone())?;
let mut proxy: Vec<PinnedFuture<(Result<()>, &str)>> = Vec::new();
if socks_port != 0 {

View File

@ -20,24 +20,6 @@ use crate::{ArtiCombinedConfig, ArtiConfig};
/// How long to wait after a file is created, before we try to read it.
const DEBOUNCE_INTERVAL: Duration = Duration::from_secs(1);
/// Find the configuration files and prepare a watcher
///
/// For the watching to be reliably effective (race-free), the config must be read
/// *after* this point, using the returned `FoundConfigFiles`.
fn prepare_watcher<'a>(
watcher: &mut FileWatcher,
sources: &'a ConfigurationSources,
) -> anyhow::Result<FoundConfigFiles<'a>> {
let sources = sources.scan()?;
for source in sources.iter() {
match source {
ConfigurationSource::Dir(dir) => watcher.watch_dir(dir)?,
ConfigurationSource::File(file) => watcher.watch_file(file)?,
}
}
Ok(sources)
}
/// Unwrap first expression or break with the provided error message
macro_rules! ok_or_break {
($e:expr, $msg:expr $(,)?) => {
@ -51,10 +33,11 @@ macro_rules! ok_or_break {
};
}
/// Launch a thread to watch our configuration files.
/// Launch a thread to reload our configuration files.
///
/// Whenever one or more files in `files` changes, try to reload our
/// configuration from them and tell TorClient about it.
/// If current configuration requires it, watch for changes in `sources`
/// and try to reload our configuration. On unix platforms, also watch
/// for SIGHUP and reload configuration then.
#[cfg_attr(feature = "experimental-api", visibility::make(pub))]
pub(crate) fn watch_for_config_changes<R: Runtime>(
sources: ConfigurationSources,
@ -69,8 +52,7 @@ pub(crate) fn watch_for_config_changes<R: Runtime>(
// we have set up the watcher *after* loading the config.
// ignore send error, rx can't be disconnected if we are here
let _ = tx.send(notify::DebouncedEvent::Rescan);
let mut watcher = FileWatcher::new(tx.clone(), DEBOUNCE_INTERVAL)?;
prepare_watcher(&mut watcher, &sources)?;
let (watcher, _) = FileWatcher::new_prepared(tx.clone(), DEBOUNCE_INTERVAL, &sources)?;
Some(watcher)
} else {
None
@ -117,15 +99,10 @@ pub(crate) fn watch_for_config_changes<R: Runtime>(
debug!("FS event {:?}: reloading configuration.", event);
let found_files = if watcher.is_some() {
let mut new_watcher = ok_or_break!(
FileWatcher::new(tx.clone(), DEBOUNCE_INTERVAL),
"FS watch: failed to create new watcher: {}",
);
let found_files = ok_or_break!(
prepare_watcher(&mut new_watcher, &sources),
let (new_watcher, found_files) = ok_or_break!(
FileWatcher::new_prepared(tx.clone(), DEBOUNCE_INTERVAL, &sources),
"FS watch: failed to rescan config and re-establish watch: {}",
);
watcher = Some(new_watcher);
found_files
} else {
@ -136,20 +113,18 @@ pub(crate) fn watch_for_config_changes<R: Runtime>(
Ok(watch) => {
info!("Successfully reloaded configuration.");
if watch && watcher.is_none() {
info!("Starting watching over configuration.");
// If watching, we must reload the config once right away, because
// we have set up the watcher *after* loading the config.
// ignore send error, rx can't be disconnected if we are here
let _ = tx.send(notify::DebouncedEvent::Rescan);
let mut new_watcher = ok_or_break!(
FileWatcher::new(tx.clone(), DEBOUNCE_INTERVAL),
"FS watch: failed to restart watching: {}",
);
ok_or_break!(
prepare_watcher(&mut new_watcher, &sources),
"FS watch: failed to rescan configuration: {}",
let (new_watcher, _) = ok_or_break!(
FileWatcher::new_prepared(tx.clone(), DEBOUNCE_INTERVAL, &sources),
"FS watch: failed to rescan config and re-establish watch: {}",
);
watcher = Some(new_watcher);
} else if !watch && watcher.is_some() {
info!("Stopped watching over configuration.");
watcher = None;
}
}
@ -236,6 +211,33 @@ impl FileWatcher {
})
}
/// Create a FileWatcher already watching files in `sources`
fn new_prepared(
tx: Sender<notify::DebouncedEvent>,
interval: Duration,
sources: &ConfigurationSources,
) -> anyhow::Result<(Self, FoundConfigFiles)> {
Self::new(tx, interval).and_then(|mut this| this.prepare(sources).map(|cfg| (this, cfg)))
}
/// Find the configuration files and prepare the watcher
///
/// For the watching to be reliably effective (race-free), the config must be read
/// *after* this point, using the returned `FoundConfigFiles`.
fn prepare<'a>(
&mut self,
sources: &'a ConfigurationSources,
) -> anyhow::Result<FoundConfigFiles<'a>> {
let sources = sources.scan()?;
for source in sources.iter() {
match source {
ConfigurationSource::Dir(dir) => self.watch_dir(dir)?,
ConfigurationSource::File(file) => self.watch_file(file)?,
}
}
Ok(sources)
}
/// Watch a single file (not a directory).
///
/// Idempotent: does nothing if we're already watching that file.