diff --git a/examples/Cargo.toml b/examples/Cargo.toml index f6f54379..e88e7fec 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -21,6 +21,10 @@ path = "monitor_raw.rs" name = "debounced" path = "debounced.rs" +[[example]] +name = "debounced_custom" +path = "debounced_full_custom.rs" + [[example]] name = "poll_sysfs" path = "poll_sysfs.rs" diff --git a/examples/async_monitor.rs b/examples/async_monitor.rs index 12e56bce..c0b0e834 100644 --- a/examples/async_monitor.rs +++ b/examples/async_monitor.rs @@ -2,7 +2,7 @@ use futures::{ channel::mpsc::{channel, Receiver}, SinkExt, StreamExt, }; -use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher}; +use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher, Config}; use std::path::Path; /// Async, futures channel based event watching @@ -28,7 +28,7 @@ fn async_watcher() -> notify::Result<(RecommendedWatcher, Receiver(Duration::from_secs(2), None, tx).unwrap(); + let mut debouncer = new_debouncer_opt::<_,notify::PollWatcher>(Duration::from_secs(2), None, tx, Config::default()).unwrap(); debouncer .watcher() diff --git a/examples/hot_reload_tide/src/main.rs b/examples/hot_reload_tide/src/main.rs index c2e06834..adfcf761 100644 --- a/examples/hot_reload_tide/src/main.rs +++ b/examples/hot_reload_tide/src/main.rs @@ -38,7 +38,7 @@ async fn main() -> tide::Result<()> { Err(error) => println!("Error reloading config: {:?}", error), } } - })?; + },notify::Config::default())?; watcher.watch(Path::new(CONFIG_PATH), RecursiveMode::Recursive)?; diff --git a/examples/monitor_raw.rs b/examples/monitor_raw.rs index 7effcf0d..8c018c87 100644 --- a/examples/monitor_raw.rs +++ b/examples/monitor_raw.rs @@ -1,4 +1,4 @@ -use notify::{RecommendedWatcher, RecursiveMode, Watcher}; +use notify::{RecommendedWatcher, RecursiveMode, Watcher, Config}; use std::path::Path; fn main() { @@ -16,7 +16,7 @@ fn watch>(path: P) -> notify::Result<()> { // Automatically select the best implementation for your platform. // You can also access each implementation directly e.g. INotifyWatcher. - let mut watcher = RecommendedWatcher::new(tx)?; + let mut watcher = RecommendedWatcher::new(tx, Config::default())?; // Add a path to be watched. All files and directories at that path and // below will be monitored for changes. diff --git a/examples/poll_sysfs.rs b/examples/poll_sysfs.rs index 067abfd9..2969a61e 100644 --- a/examples/poll_sysfs.rs +++ b/examples/poll_sysfs.rs @@ -3,8 +3,7 @@ /// This example can't be demonstrated under windows, it might be relevant for network shares #[cfg(not(target_os = "windows"))] fn not_windows_main() -> notify::Result<()> { - use notify::poll::PollWatcherConfig; - use notify::{PollWatcher, RecursiveMode, Watcher}; + use notify::{PollWatcher, RecursiveMode, Watcher, Config}; use std::path::Path; use std::time::Duration; @@ -27,13 +26,12 @@ fn not_windows_main() -> notify::Result<()> { println!("watching {:?}...", paths); // configure pollwatcher backend - let config = PollWatcherConfig { - compare_contents: true, // crucial part for pseudo filesystems - poll_interval: Duration::from_secs(2), - }; + let config = Config::default() + .with_compare_contents(true) // crucial part for pseudo filesystems + .with_poll_interval(Duration::from_secs(2)); let (tx, rx) = std::sync::mpsc::channel(); // create pollwatcher backend - let mut watcher = PollWatcher::with_config(tx, config)?; + let mut watcher = PollWatcher::new(tx, config)?; for path in paths { // watch all paths watcher.watch(&path, RecursiveMode::Recursive)?; diff --git a/examples/watcher_kind.rs b/examples/watcher_kind.rs index a74bcfc3..6c7ea745 100644 --- a/examples/watcher_kind.rs +++ b/examples/watcher_kind.rs @@ -1,18 +1,20 @@ use std::{path::Path, time::Duration}; +use notify::*; -use notify::{poll::PollWatcherConfig, *}; +// exampale of detecting the recommended watcher kind fn main() { let (tx, rx) = std::sync::mpsc::channel(); + // This example is a little bit misleading as you can just create one Config and use it for all watchers. + // That way the pollwatcher specific stuff is still configured, if it should be used. let mut watcher: Box = if RecommendedWatcher::kind() == WatcherKind::PollWatcher { // custom config for PollWatcher kind - let config = PollWatcherConfig { - poll_interval: Duration::from_secs(1), - ..Default::default() - }; - Box::new(PollWatcher::with_config(tx, config).unwrap()) + // you + let config = Config::default() + .with_poll_interval(Duration::from_secs(1)); + Box::new(PollWatcher::new(tx, config).unwrap()) } else { // use default config for everything else - Box::new(RecommendedWatcher::new(tx).unwrap()) + Box::new(RecommendedWatcher::new(tx, Config::default()).unwrap()) }; // watch some stuff diff --git a/notify-debouncer-mini/src/lib.rs b/notify-debouncer-mini/src/lib.rs index efa5fd4b..1fcc9950 100644 --- a/notify-debouncer-mini/src/lib.rs +++ b/notify-debouncer-mini/src/lib.rs @@ -4,7 +4,6 @@ //! //! ```toml //! [dependencies] -//! notify = "5.0.0-pre.15" //! notify-debouncer-mini = "0.1" //! ``` //! @@ -13,10 +12,12 @@ //! ```rust,no_run //! # use std::path::Path; //! # use std::time::Duration; -//! use notify::{Watcher, RecursiveMode, Result}; -//! use notify_debouncer_mini::{new_debouncer,DebounceEventResult}; +//! use notify_debouncer_mini::{notify::*,new_debouncer,DebounceEventResult}; //! //! # fn main() { +//! // setup initial watcher backend config +//! let config = Config::default(); +//! //! // Select recommended watcher for debouncer. //! // Using a callback here, could also be a channel. //! let mut debouncer = new_debouncer(Duration::from_secs(2), None, |res: DebounceEventResult| { @@ -50,6 +51,7 @@ use std::{ time::{Duration, Instant}, }; +pub use notify; use notify::{Error, ErrorKind, Event, RecommendedWatcher, Watcher}; /// The set of requirements for watcher debounce event handling functions. @@ -259,6 +261,7 @@ pub fn new_debouncer_opt( timeout: Duration, tick_rate: Option, mut event_handler: F, + config: notify::Config ) -> Result, Error> { let data = DebounceData::default(); @@ -320,7 +323,7 @@ pub fn new_debouncer_opt( // can't have multiple TX, so we need to pipe that through our debouncer Err(e) => lock.add_error(e), } - })?; + }, config)?; let guard = Debouncer { watcher, @@ -339,7 +342,7 @@ pub fn new_debouncer_opt( pub fn new_debouncer( timeout: Duration, tick_rate: Option, - event_handler: F, + event_handler: F ) -> Result, Error> { - new_debouncer_opt::(timeout, tick_rate, event_handler) + new_debouncer_opt::(timeout, tick_rate, event_handler, notify::Config::default()) } diff --git a/notify/src/config.rs b/notify/src/config.rs index 5b12e406..091601b8 100644 --- a/notify/src/config.rs +++ b/notify/src/config.rs @@ -21,42 +21,72 @@ impl RecursiveMode { } } -/// Runtime configuration items for watchers. -/// -/// See the [`Watcher::configure`](../trait.Watcher.html#tymethod.configure) method for usage. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum Config { - /// Enable or disable emitting precise event classification. - /// - /// Applicable to all watchers. - /// - /// When enabled, events are emitted with a `kind` set to as much precision about what kind of - /// event they are as the backend is capable of providing. When disabled (default), events are - /// instead emitted as `EventKind::Any`. `EventKind::Other` meta-events are left alone. - PreciseEvents(bool), - - /// Enable or disable emitting `Notice` events. - /// - /// Applicable to debounced watchers only. - /// - /// When enabled, the first modify or remove event for a path is emitted immediately with a - /// [`Flag::Notice`](../event/enum.Flag.html) attribute within a debouncing period, enabling - /// applications to respond more quickly. - NoticeEvents(bool), - - /// Enable or disable emitting `Ongoing` events. - /// - /// Applicable to debounced watchers only. - /// - /// When enabled, partial write events that are received after a `Modify(Data)` Notice but - /// before the end of a debouncing period (and the emission of a `Modify(Data)` event) are - /// passed through as `Modify(Data)` events with an `Ongoing` flag. These events are still - /// debounced, but at a lower (configurable) interval than the debouncing interval. - /// - /// To enable, provide `Some(Duration)`. To disable, provide `None`. - /// - /// # Errors - /// - /// - `InvalidConfigValue` if the interval provided is higher than the debounce interval. - OngoingEvents(Option), +/// Watcher Backend configuration +/// +/// This contains multiple settings that may relate to only one specific backend, +/// such as to correctly configure each backend regardless of what is selected during runtime. +/// +/// ```rust +/// # use std::time::Duration; +/// # use notify::Config; +/// let config = Config::default() +/// .with_poll_interval(Duration::from_secs(2)) +/// .with_compare_contents(true); +/// ``` +/// +/// Some options can be changed during runtime, others have to be set when creating the watcher backend. +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub struct Config { + /// See [BackendConfig::with_poll_interval] + poll_interval: Duration, + + /// See [BackendConfig::with_compare_contents] + compare_contents: bool, } + +impl Config { + /// For [crate::PollWatcher] + /// + /// Interval between each rescan attempt. This can be extremely expensive for large + /// file trees so it is recommended to measure and tune accordingly. + /// + /// The default poll frequency is 30 seconds. + pub fn with_poll_interval(mut self, dur: Duration) -> Self { + self.poll_interval = dur; + self + } + + /// Returns current setting + pub fn poll_interval(&self) -> Duration { + self.poll_interval + } + + /// For [crate::PollWatcher] + /// + /// Optional feature that will evaluate the contents of changed files to determine if + /// they have indeed changed using a fast hashing algorithm. This is especially important + /// for pseudo filesystems like those on Linux under /sys and /proc which are not obligated + /// to respect any other filesystem norms such as modification timestamps, file sizes, etc. + /// By enabling this feature, performance will be significantly impacted as all files will + /// need to be read and hashed at each `poll_interval`. + /// + /// This can't be changed during runtime. Off by default. + pub fn with_compare_contents(mut self, compare_contents: bool) -> Self { + self.compare_contents = compare_contents; + self + } + + /// Returns current setting + pub fn compare_contents(&self) -> bool { + self.compare_contents + } +} + +impl Default for Config { + fn default() -> Self { + Self { + poll_interval: Duration::from_secs(30), + compare_contents: false + } + } +} \ No newline at end of file diff --git a/notify/src/fsevent.rs b/notify/src/fsevent.rs index b6b23e96..c52ae391 100644 --- a/notify/src/fsevent.rs +++ b/notify/src/fsevent.rs @@ -543,7 +543,7 @@ unsafe fn callback_impl( impl Watcher for FsEventWatcher { /// Create a new watcher. - fn new(event_handler: F) -> Result { + fn new(event_handler: F, _config: Config) -> Result { Self::from_event_handler(Arc::new(Mutex::new(event_handler))) } diff --git a/notify/src/inotify.rs b/notify/src/inotify.rs index a85ac626..174c5038 100644 --- a/notify/src/inotify.rs +++ b/notify/src/inotify.rs @@ -617,7 +617,7 @@ impl INotifyWatcher { impl Watcher for INotifyWatcher { /// Create a new watcher. - fn new(event_handler: F) -> Result { + fn new(event_handler: F, _config: Config) -> Result { Self::from_event_handler(Box::new(event_handler)) } diff --git a/notify/src/kqueue.rs b/notify/src/kqueue.rs index aac7c34e..61858c0a 100644 --- a/notify/src/kqueue.rs +++ b/notify/src/kqueue.rs @@ -5,7 +5,7 @@ //! pieces of kernel code termed filters. use super::event::*; -use super::{Error, EventHandler, RecursiveMode, Result, Watcher}; +use super::{Error, EventHandler, RecursiveMode, Result, Watcher, Config}; use crate::{unbounded, Receiver, Sender}; use kqueue::{EventData, EventFilter, FilterFlag, Ident}; use std::collections::HashMap; @@ -405,7 +405,7 @@ impl KqueueWatcher { impl Watcher for KqueueWatcher { /// Create a new watcher. - fn new(event_handler: F) -> Result { + fn new(event_handler: F, _config: Config) -> Result { Self::from_event_handler(Box::new(event_handler)) } diff --git a/notify/src/lib.rs b/notify/src/lib.rs index b0bd53f8..b63f6aab 100644 --- a/notify/src/lib.rs +++ b/notify/src/lib.rs @@ -290,8 +290,8 @@ pub enum WatcherKind { /// In addition to such event driven implementations, a polling implementation is also provided /// that should work on any platform. pub trait Watcher { - /// Create a new watcher. - fn new(event_handler: F) -> Result + /// Create a new watcher with an initial Config. + fn new(event_handler: F, config: config::Config) -> Result where Self: Sized; /// Begin watching a new path. @@ -377,7 +377,7 @@ where F: EventHandler, { // All recommended watchers currently implement `new`, so just call that. - RecommendedWatcher::new(event_handler) + RecommendedWatcher::new(event_handler, Config::default()) } #[cfg(test)] diff --git a/notify/src/null.rs b/notify/src/null.rs index 27daa526..bbcd80d9 100644 --- a/notify/src/null.rs +++ b/notify/src/null.rs @@ -2,6 +2,8 @@ #![allow(unused_variables)] +use crate::Config; + use super::{RecursiveMode, Result, Watcher}; use std::path::Path; @@ -20,13 +22,17 @@ impl Watcher for NullWatcher { Ok(()) } - fn new(event_handler: F) -> Result + fn new(event_handler: F, config: Config) -> Result where Self: Sized, { Ok(NullWatcher) } + fn configure(&mut self, config: Config) -> Result { + Ok(false) + } + fn kind() -> crate::WatcherKind { crate::WatcherKind::NullWatcher } diff --git a/notify/src/poll.rs b/notify/src/poll.rs index 186dad00..8e1232a5 100644 --- a/notify/src/poll.rs +++ b/notify/src/poll.rs @@ -3,7 +3,7 @@ //! Checks the `watch`ed paths periodically to detect changes. This implementation only uses //! Rust stdlib APIs and should work on all of the platforms it supports. -use crate::{EventHandler, RecursiveMode, Watcher}; +use crate::{EventHandler, RecursiveMode, Watcher, Config}; use std::{ collections::HashMap, path::{Path, PathBuf}, @@ -406,45 +406,19 @@ pub struct PollWatcher { delay: Duration, } -/// General purpose configuration for [`PollWatcher`] specifically. Can be used to tune -/// this watcher differently than the other platform specific ones. -#[derive(Debug, Clone)] -pub struct PollWatcherConfig { - /// Interval between each rescan attempt. This can be extremely expensive for large - /// file trees so it is recommended to measure and tune accordingly. - pub poll_interval: Duration, - - /// Optional feature that will evaluate the contents of changed files to determine if - /// they have indeed changed using a fast hashing algorithm. This is especially important - /// for pseudo filesystems like those on Linux under /sys and /proc which are not obligated - /// to respect any other filesystem norms such as modification timestamps, file sizes, etc. - /// By enabling this feature, performance will be significantly impacted as all files will - /// need to be read and hashed at each `poll_interval`. - pub compare_contents: bool, -} - -impl Default for PollWatcherConfig { - fn default() -> Self { - Self { - poll_interval: Duration::from_secs(30), - compare_contents: false, - } - } -} - impl PollWatcher { /// Create a new [PollWatcher], configured as needed. - pub fn with_config( + pub fn new( event_handler: F, - config: PollWatcherConfig, + config: Config, ) -> crate::Result { - let data_builder = DataBuilder::new(event_handler, config.compare_contents); + let data_builder = DataBuilder::new(event_handler, config.compare_contents()); let poll_watcher = PollWatcher { watches: Default::default(), data_builder: Arc::new(Mutex::new(data_builder)), want_to_stop: Arc::new(AtomicBool::new(false)), - delay: config.poll_interval, + delay: config.poll_interval(), }; poll_watcher.run(); @@ -535,11 +509,8 @@ impl PollWatcher { impl Watcher for PollWatcher { /// Create a new [PollWatcher]. - /// - /// The default poll frequency is 30 seconds. - /// Use [PollWatcher::with_config] to manually set the poll frequency. - fn new(event_handler: F) -> crate::Result { - Self::with_config(event_handler, PollWatcherConfig::default()) + fn new(event_handler: F, config: Config) -> crate::Result { + Self::new(event_handler, config) } fn watch(&mut self, path: &Path, recursive_mode: RecursiveMode) -> crate::Result<()> { diff --git a/notify/src/windows.rs b/notify/src/windows.rs index d5a90f76..9a032241 100644 --- a/notify/src/windows.rs +++ b/notify/src/windows.rs @@ -15,9 +15,9 @@ use winapi::um::synchapi; use winapi::um::winbase::{self, INFINITE, WAIT_OBJECT_0}; use winapi::um::winnt::{self, FILE_NOTIFY_INFORMATION, HANDLE}; -use crate::{bounded, unbounded, BoundSender, Receiver, Sender}; +use crate::{bounded, unbounded, BoundSender, Receiver, Sender, Config}; use crate::{event::*, WatcherKind}; -use crate::{Config, Error, EventHandler, RecursiveMode, Result, Watcher}; +use crate::{Error, EventHandler, RecursiveMode, Result, Watcher}; use std::collections::HashMap; use std::env; use std::ffi::OsString; @@ -498,7 +498,7 @@ impl ReadDirectoryChangesWatcher { } impl Watcher for ReadDirectoryChangesWatcher { - fn new(event_handler: F) -> Result { + fn new(event_handler: F, config: Config) -> Result { // create dummy channel for meta event // TODO: determine the original purpose of this - can we remove it? let (meta_tx, _) = unbounded();