Skip to main content

greentic_ext_runtime/
watcher.rs

1use std::path::PathBuf;
2use std::sync::mpsc;
3use std::time::Duration;
4
5use notify::RecommendedWatcher;
6use notify::RecursiveMode;
7use notify_debouncer_full::{DebounceEventResult, Debouncer, RecommendedCache, new_debouncer};
8
9use crate::error::RuntimeError;
10
11#[derive(Debug, Clone)]
12pub enum FsEvent {
13    Added(PathBuf),
14    Modified(PathBuf),
15    Removed(PathBuf),
16}
17
18/// RAII handle that keeps the debouncer alive. Drop this to stop watching.
19pub struct WatchHandle {
20    _debouncer: Debouncer<RecommendedWatcher, RecommendedCache>,
21}
22
23/// Start watching `paths` recursively. Returns a channel receiver emitting
24/// coalesced FS events and a `WatchHandle` that owns the debouncer — drop
25/// the handle to stop watching and close the channel.
26pub fn watch(paths: &[PathBuf]) -> Result<(mpsc::Receiver<FsEvent>, WatchHandle), RuntimeError> {
27    let (tx, rx) = mpsc::channel();
28    let mut debouncer = new_debouncer(
29        Duration::from_millis(500),
30        None,
31        move |res: DebounceEventResult| {
32            if let Ok(events) = res {
33                for ev in events {
34                    for p in &ev.event.paths {
35                        let out = match ev.event.kind {
36                            notify::EventKind::Create(_) => FsEvent::Added(p.clone()),
37                            notify::EventKind::Modify(_) => FsEvent::Modified(p.clone()),
38                            notify::EventKind::Remove(_) => FsEvent::Removed(p.clone()),
39                            _ => continue,
40                        };
41                        let _ = tx.send(out);
42                    }
43                }
44            }
45        },
46    )
47    .map_err(|e| RuntimeError::Watcher(e.to_string()))?;
48
49    for p in paths {
50        if p.exists() {
51            debouncer
52                .watch(p, RecursiveMode::Recursive)
53                .map_err(|e| RuntimeError::Watcher(e.to_string()))?;
54        }
55    }
56    Ok((
57        rx,
58        WatchHandle {
59            _debouncer: debouncer,
60        },
61    ))
62}