48 lines
1.5 KiB
Rust
48 lines
1.5 KiB
Rust
|
|
use anyhow::Result;
|
||
|
|
use notify::{Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
|
||
|
|
use std::path::{Path, PathBuf};
|
||
|
|
use tokio::sync::mpsc;
|
||
|
|
use tracing::debug;
|
||
|
|
|
||
|
|
pub enum WatchEvent {
|
||
|
|
Changed(PathBuf),
|
||
|
|
Removed(PathBuf),
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Start a single notify watcher for one or more paths. All events route to the same channel.
|
||
|
|
pub fn start_many(paths: &[PathBuf]) -> Result<(RecommendedWatcher, mpsc::Receiver<WatchEvent>)> {
|
||
|
|
let (tx, rx) = mpsc::channel::<WatchEvent>(128);
|
||
|
|
|
||
|
|
let mut watcher = notify::recommended_watcher(move |res: notify::Result<Event>| {
|
||
|
|
let Ok(event) = res else { return };
|
||
|
|
let kind = event.kind;
|
||
|
|
for path in event.paths {
|
||
|
|
if path.extension().is_none_or(|e| e != "ncl") {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
let evt = match &kind {
|
||
|
|
EventKind::Remove(_) => WatchEvent::Removed(path),
|
||
|
|
_ => WatchEvent::Changed(path),
|
||
|
|
};
|
||
|
|
let _ = tx.try_send(evt);
|
||
|
|
}
|
||
|
|
})?;
|
||
|
|
|
||
|
|
for p in paths {
|
||
|
|
if p.exists() {
|
||
|
|
watcher.watch(p, RecursiveMode::Recursive)?;
|
||
|
|
debug!("watching: {}", p.display());
|
||
|
|
} else {
|
||
|
|
debug!("skip watch (not found): {}", p.display());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Ok((watcher, rx))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Convenience wrapper for single-path watching (preserves old API for tests/tools).
|
||
|
|
#[allow(dead_code)]
|
||
|
|
pub fn start(watch_path: &Path) -> Result<(RecommendedWatcher, mpsc::Receiver<WatchEvent>)> {
|
||
|
|
start_many(&[watch_path.to_path_buf()])
|
||
|
|
}
|