Skip to content

Commit 4294f07

Browse files
committed
add manual polling for PollWatcher
1 parent 22f84ca commit 4294f07

2 files changed

Lines changed: 42 additions & 22 deletions

File tree

notify/src/config.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl RecursiveMode {
3838
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
3939
pub struct Config {
4040
/// See [BackendConfig::with_poll_interval]
41-
poll_interval: Duration,
41+
poll_interval: Option<Duration>,
4242

4343
/// See [BackendConfig::with_compare_contents]
4444
compare_contents: bool,
@@ -52,15 +52,30 @@ impl Config {
5252
///
5353
/// The default poll frequency is 30 seconds.
5454
pub fn with_poll_interval(mut self, dur: Duration) -> Self {
55-
self.poll_interval = dur;
55+
// TODO: v7.0 break signature to option
56+
self.poll_interval = Some(dur);
5657
self
5758
}
5859

5960
/// Returns current setting
61+
#[deprecated(since = "6.1.0", note = "use poll_interval_v2 to account for disabled automatic polling")]
6062
pub fn poll_interval(&self) -> Duration {
63+
// TODO: v7.0 break signature to option
64+
self.poll_interval.unwrap_or_default()
65+
}
66+
67+
/// Returns current setting
68+
pub fn poll_interval_v2(&self) -> Option<Duration> {
69+
// TODO: v7.0 break signature to option
6170
self.poll_interval
6271
}
6372

73+
/// Disable automatic polling. Requires calling [crate::PollWatcher::poll] manually.
74+
pub fn with_manual_polling(mut self) -> Self {
75+
self.poll_interval = None;
76+
self
77+
}
78+
6479
/// For [crate::PollWatcher]
6580
///
6681
/// Optional feature that will evaluate the contents of changed files to determine if
@@ -85,7 +100,7 @@ impl Config {
85100
impl Default for Config {
86101
fn default() -> Self {
87102
Self {
88-
poll_interval: Duration::from_secs(30),
103+
poll_interval: Some(Duration::from_secs(5)),
89104
compare_contents: false,
90105
}
91106
}

notify/src/poll.rs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! Checks the `watch`ed paths periodically to detect changes. This implementation only uses
44
//! Rust stdlib APIs and should work on all of the platforms it supports.
55
6-
use crate::{Config, EventHandler, RecursiveMode, Watcher};
6+
use crate::{Config, EventHandler, RecursiveMode, Watcher, Sender, unbounded, Receiver, Error};
77
use std::{
88
collections::HashMap,
99
path::{Path, PathBuf},
@@ -22,7 +22,6 @@ pub type ScanEvent = crate::Result<PathBuf>;
2222
/// Very much the same as [EventHandler], but including the Result.
2323
///
2424
/// See the full example for more information.
25-
/// ```
2625
pub trait ScanEventHandler: Send + 'static {
2726
/// Handles an event.
2827
fn handle_event(&mut self, event: ScanEvent);
@@ -477,7 +476,10 @@ pub struct PollWatcher {
477476
watches: Arc<Mutex<HashMap<PathBuf, WatchData>>>,
478477
data_builder: Arc<Mutex<DataBuilder>>,
479478
want_to_stop: Arc<AtomicBool>,
480-
delay: Duration,
479+
/// channel to the poll loop
480+
/// currently used only for active polling
481+
message_channel: Sender<()>,
482+
delay: Option<Duration>,
481483
}
482484

483485
impl PollWatcher {
@@ -486,6 +488,12 @@ impl PollWatcher {
486488
Self::with_opt::<_, ()>(event_handler, config, None)
487489
}
488490

491+
/// Actively poll for changes. Can be combined with a timeout of 0 to perform only manual polling.
492+
pub fn poll(&self) -> crate::Result<()> {
493+
self.message_channel.send(()).map_err(|_|Error::generic("failed to send poll message"))?;
494+
Ok(())
495+
}
496+
489497
/// Create a new [PollWatcher] with an scan event handler.
490498
///
491499
/// `scan_fallback` is called on the initial scan with all files seen by the pollwatcher.
@@ -497,7 +505,7 @@ impl PollWatcher {
497505
Self::with_opt(event_handler, config, Some(scan_callback))
498506
}
499507

500-
/// create a new pollwatcher with all options
508+
/// create a new PollWatcher with all options
501509
fn with_opt<F: EventHandler, G: ScanEventHandler>(
502510
event_handler: F,
503511
config: Config,
@@ -506,19 +514,22 @@ impl PollWatcher {
506514
let data_builder =
507515
DataBuilder::new(event_handler, config.compare_contents(), scan_callback);
508516

517+
let (tx, rx) = unbounded();
518+
509519
let poll_watcher = PollWatcher {
510520
watches: Default::default(),
511521
data_builder: Arc::new(Mutex::new(data_builder)),
512522
want_to_stop: Arc::new(AtomicBool::new(false)),
513-
delay: config.poll_interval(),
523+
delay: config.poll_interval_v2(),
524+
message_channel: tx,
514525
};
515526

516-
poll_watcher.run();
527+
poll_watcher.run(rx);
517528

518529
Ok(poll_watcher)
519530
}
520531

521-
fn run(&self) {
532+
fn run(&self, rx: Receiver<()>) {
522533
let watches = Arc::clone(&self.watches);
523534
let data_builder = Arc::clone(&self.data_builder);
524535
let want_to_stop = Arc::clone(&self.want_to_stop);
@@ -546,18 +557,12 @@ impl PollWatcher {
546557
watch_data.rescan(&mut data_builder);
547558
}
548559
}
549-
550-
// QUESTION: `actual_delay == process_time + delay`. Is it intended to?
551-
//
552-
// If not, consider fix it to:
553-
//
554-
// ```rust
555-
// let still_need_to_delay = delay.checked_sub(data_builder.now.elapsed());
556-
// if let Some(delay) = still_need_to_delay {
557-
// thread::sleep(delay);
558-
// }
559-
// ```
560-
thread::sleep(delay);
560+
// TODO: v7.0 use delay - (Instant::now().saturating_duration_since(start))
561+
if let Some(delay) = delay {
562+
let _ = rx.recv_timeout(delay);
563+
} else {
564+
let _ = rx.recv();
565+
}
561566
}
562567
});
563568
}

0 commit comments

Comments
 (0)