Allow specifying polling/debounce frequency.
parent
7db0656e89
commit
c6bd229640
|
@ -14,9 +14,6 @@ use std::time::Duration;
|
||||||
// TODO(jrpotter): Add logging.
|
// TODO(jrpotter): Add logging.
|
||||||
// TODO(jrpotter): Add pid file to only allow one daemon at a time.
|
// TODO(jrpotter): Add pid file to only allow one daemon at a time.
|
||||||
|
|
||||||
// Used for both polling and debouncing file system events.
|
|
||||||
const WATCH_FREQUENCY: Duration = Duration::from_secs(5);
|
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
// Polling
|
// Polling
|
||||||
// ========================================
|
// ========================================
|
||||||
|
@ -49,7 +46,7 @@ fn resolve_pending(tx: &Sender<DebouncedEvent>, pending: &HashSet<PathBuf>) -> V
|
||||||
to_remove
|
to_remove
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_pending(tx: Sender<DebouncedEvent>, rx: Receiver<PollEvent>) {
|
fn poll_pending(tx: Sender<DebouncedEvent>, rx: Receiver<PollEvent>, freq_secs: u64) {
|
||||||
let mut pending = HashSet::new();
|
let mut pending = HashSet::new();
|
||||||
loop {
|
loop {
|
||||||
match rx.try_recv() {
|
match rx.try_recv() {
|
||||||
|
@ -61,7 +58,7 @@ fn poll_pending(tx: Sender<DebouncedEvent>, rx: Receiver<PollEvent>) {
|
||||||
resolve_pending(&tx, &pending).iter().for_each(|r| {
|
resolve_pending(&tx, &pending).iter().for_each(|r| {
|
||||||
pending.remove(r);
|
pending.remove(r);
|
||||||
});
|
});
|
||||||
thread::sleep(WATCH_FREQUENCY);
|
thread::sleep(Duration::from_secs(freq_secs));
|
||||||
}
|
}
|
||||||
Err(TryRecvError::Disconnected) => panic!("Polling channel closed."),
|
Err(TryRecvError::Disconnected) => panic!("Polling channel closed."),
|
||||||
}
|
}
|
||||||
|
@ -142,7 +139,7 @@ impl<'a> WatchState<'a> {
|
||||||
// Daemon
|
// Daemon
|
||||||
// ========================================
|
// ========================================
|
||||||
|
|
||||||
pub fn launch(mut config: PathConfig) -> Result<(), Box<dyn Error>> {
|
pub fn launch(mut config: PathConfig, freq_secs: u64) -> Result<(), Box<dyn Error>> {
|
||||||
let (poll_tx, poll_rx) = channel();
|
let (poll_tx, poll_rx) = channel();
|
||||||
let (watch_tx, watch_rx) = channel();
|
let (watch_tx, watch_rx) = channel();
|
||||||
let watch_tx1 = watch_tx.clone();
|
let watch_tx1 = watch_tx.clone();
|
||||||
|
@ -150,12 +147,12 @@ pub fn launch(mut config: PathConfig) -> Result<(), Box<dyn Error>> {
|
||||||
// watch, but this fails if no file exists at the given path. In these
|
// watch, but this fails if no file exists at the given path. In these
|
||||||
// cases, we rely on a basic polling strategy to check if the files ever
|
// cases, we rely on a basic polling strategy to check if the files ever
|
||||||
// come into existence.
|
// come into existence.
|
||||||
thread::spawn(move || poll_pending(watch_tx, poll_rx));
|
thread::spawn(move || poll_pending(watch_tx, poll_rx, freq_secs));
|
||||||
// Track our original config file separately from the other files that may
|
// Track our original config file separately from the other files that may
|
||||||
// be defined in the config. We want to make sure we're always alerted on
|
// be defined in the config. We want to make sure we're always alerted on
|
||||||
// changes to it for hot reloading purposes, and not worry that our wrapper
|
// changes to it for hot reloading purposes, and not worry that our wrapper
|
||||||
// will ever clear it from its watch state.
|
// will ever clear it from its watch state.
|
||||||
let mut watcher: RecommendedWatcher = Watcher::new(watch_tx1, WATCH_FREQUENCY)?;
|
let mut watcher: RecommendedWatcher = Watcher::new(watch_tx1, Duration::from_secs(freq_secs))?;
|
||||||
watcher.watch(&config.0, RecursiveMode::NonRecursive)?;
|
watcher.watch(&config.0, RecursiveMode::NonRecursive)?;
|
||||||
let mut state = WatchState::new(poll_tx, &mut watcher)?;
|
let mut state = WatchState::new(poll_tx, &mut watcher)?;
|
||||||
state.update(&config);
|
state.update(&config);
|
||||||
|
|
|
@ -13,8 +13,8 @@ pub fn run_add(_config: PathConfig) -> Result<(), config::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_daemon(config: PathConfig) -> Result<(), Box<dyn Error>> {
|
pub fn run_daemon(config: PathConfig, freq_secs: u64) -> Result<(), Box<dyn Error>> {
|
||||||
daemon::launch(config)?;
|
daemon::launch(config, freq_secs)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
33
src/main.rs
33
src/main.rs
|
@ -19,7 +19,25 @@ fn main() {
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.subcommand(App::new("add").about("Add new configuration to local repository"))
|
.subcommand(App::new("add").about("Add new configuration to local repository"))
|
||||||
.subcommand(App::new("daemon").about("Start up a new homesync daemon"))
|
.subcommand(
|
||||||
|
App::new("daemon")
|
||||||
|
.about("Start up a new homesync daemon")
|
||||||
|
.arg(
|
||||||
|
Arg::new("frequency")
|
||||||
|
.short('f')
|
||||||
|
.long("frequency")
|
||||||
|
.value_name("FREQUENCY")
|
||||||
|
.help("How often (in seconds) we poll/debounce file system changes")
|
||||||
|
.long_help(
|
||||||
|
"There exists a balance between how responsive changes are \
|
||||||
|
made and how expensive it is to look for changes. \
|
||||||
|
Empirically we found the default value to offer a nice \
|
||||||
|
compromise but this can be tweaked based on preference.",
|
||||||
|
)
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value("5"),
|
||||||
|
),
|
||||||
|
)
|
||||||
.subcommand(App::new("init").about("Initialize the homesync local repository"))
|
.subcommand(App::new("init").about("Initialize the homesync local repository"))
|
||||||
.subcommand(App::new("list").about("See which packages homesync manages"))
|
.subcommand(App::new("list").about("See which packages homesync manages"))
|
||||||
.subcommand(App::new("pull").about("Pull remote repository into local repository"))
|
.subcommand(App::new("pull").about("Pull remote repository into local repository"))
|
||||||
|
@ -44,7 +62,18 @@ fn dispatch(matches: clap::ArgMatches) -> Result<(), Box<dyn Error>> {
|
||||||
let config = homesync::config::load(&candidates)?;
|
let config = homesync::config::load(&candidates)?;
|
||||||
match subcommand {
|
match subcommand {
|
||||||
Some(("add", _)) => Ok(homesync::run_add(config)?),
|
Some(("add", _)) => Ok(homesync::run_add(config)?),
|
||||||
Some(("daemon", _)) => Ok(homesync::run_daemon(config)?),
|
Some(("daemon", matches)) => {
|
||||||
|
let freq_secs: u64 = match matches.value_of("frequency") {
|
||||||
|
Some(f) => f.parse().unwrap_or(0),
|
||||||
|
None => 5,
|
||||||
|
};
|
||||||
|
if freq_secs > 0 {
|
||||||
|
homesync::run_daemon(config, freq_secs)?;
|
||||||
|
} else {
|
||||||
|
eprintln!("Invalid frequency. Expected a positive integer.");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Some(("list", _)) => Ok(homesync::run_list(config)?),
|
Some(("list", _)) => Ok(homesync::run_list(config)?),
|
||||||
Some(("pull", _)) => Ok(homesync::run_pull(config)?),
|
Some(("pull", _)) => Ok(homesync::run_pull(config)?),
|
||||||
Some(("push", _)) => Ok(homesync::run_push(config)?),
|
Some(("push", _)) => Ok(homesync::run_push(config)?),
|
||||||
|
|
Loading…
Reference in New Issue