diff --git a/Cargo.lock b/Cargo.lock index cf497f9..86ac98e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1346,6 +1346,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "notify-debouncer-mini" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c538ea1dd436b41e751922510cfbcaea2def87ed6ed94aa1edc15dc31b4c179" +dependencies = [ + "crossbeam-channel", + "notify", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -1993,6 +2003,7 @@ dependencies = [ "mime_guess", "nom", "notify", + "notify-debouncer-mini", "once_cell", "phf", "phf_codegen", diff --git a/Cargo.toml b/Cargo.toml index df681ca..94b3dc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ mime = "0.3.16" mime_guess = { version = "2.0.4", default-features = false } nom = { version = "7.1.1", default-features = false, features = [ "alloc" ] } notify = "5.0.0" +notify-debouncer-mini = "0.2.0" once_cell = { version = "1.13.1", default-features = false } phf = "0.11.1" regex = { version = "1.6.0", default-features = false } diff --git a/src/package/watcher.rs b/src/package/watcher.rs index ae1a12f..5e618ba 100644 --- a/src/package/watcher.rs +++ b/src/package/watcher.rs @@ -17,7 +17,9 @@ // SPDX-License-Identifier: AGPL-3.0-or-later use crate::{AUTH_DATA, PACKAGE_LIST, SETTINGS}; -use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; +use notify::{RecommendedWatcher, RecursiveMode}; +use notify_debouncer_mini::{new_debouncer, DebounceEventResult, DebouncedEvent, Debouncer}; + use std::{ ffi::OsStr, path::Path, @@ -28,16 +30,18 @@ use std::{ }; pub struct PackageWatcher<'a> { - inner: RecommendedWatcher, + // We need to keep the reference around, to prevent it from being dropped + #[allow(dead_code)] + inner: Debouncer, + path: &'a Path, scanning: Arc>, } impl<'a> PackageWatcher<'a> { - pub fn new(path: &'a Path, tx: Sender) -> notify::Result { - let mut inner = notify::watcher(tx, std::time::Duration::from_secs(5))?; - - inner.watch(&path, RecursiveMode::Recursive)?; + pub fn new(path: &'a Path, tx: Sender) -> notify::Result { + let mut inner = new_debouncer(std::time::Duration::from_secs(5), None, tx)?; + inner.watcher().watch(path, RecursiveMode::Recursive)?; let watcher = Self { inner, @@ -88,45 +92,38 @@ impl<'a> PackageWatcher<'a> { } fn handle_event(&self, event: DebouncedEvent) { - match event { - DebouncedEvent::NoticeWrite(ref path) - | DebouncedEvent::NoticeRemove(ref path) - | DebouncedEvent::Create(ref path) - | DebouncedEvent::Write(ref path) - | DebouncedEvent::Chmod(ref path) - | DebouncedEvent::Remove(ref path) - | DebouncedEvent::Rename(ref path, _) => { - if path.extension() == Some(OsStr::new("tar")) - || path == &self.path.join("auth.json") - { - log::trace!("Re-scan triggered by event: {:#?}", event); - self.start_scan(); - } - } - DebouncedEvent::Rescan => { - log::trace!("Re-scan triggered by DebouncedEvent::Rescan"); - self.start_scan(); - } - DebouncedEvent::Error(..) => { - unreachable!("Error events have been handled in `start_thread` already"); - } + // TODO: Previously we also scanned when we got a "Rescan" event. + // We might have to scan when we get an event where `event.path == self.path`. + + if event.path.extension() == Some(OsStr::new("tar")) + || event.path == self.path.join("auth.json") + { + log::trace!("Re-scan triggered by event: {:#?}", event); + self.start_scan(); } } - pub fn start_watcher(&mut self, rx: Receiver) { + pub fn start_watcher(&mut self, rx: Receiver) { loop { match rx.recv() { - Ok(DebouncedEvent::Error(err, Some(path))) => { - log::error!("Watch error in path {:?}: {:?}", path, err); - } - Ok(DebouncedEvent::Error(err, None)) => { - log::error!("Watch error: {:?}", err); - } Err(err) => { log::error!("Generic watch error, stopping loop: {:?}", err); break; } - Ok(event) => self.handle_event(event), + Ok(Ok(events)) => { + for event in events { + self.handle_event(event) + } + } + Ok(Err(errors)) => { + log::error!( + "Encountered {} errors while processing events:", + errors.len() + ); + for (i, err) in errors.iter().enumerate() { + log::error!("Error #{i}: {err}"); + } + } } } } @@ -139,9 +136,3 @@ impl std::fmt::Debug for PackageWatcher<'_> { .finish() } } - -impl Drop for PackageWatcher<'_> { - fn drop(&mut self) { - self.inner.unwatch(&self.path).unwrap(); - } -}