use std::{
cell::Cell,
fs,
path::PathBuf,
sync::mpsc::Sender,
time::{Duration, SystemTime},
};
use notify::{RecommendedWatcher, RecursiveMode};
use notify_debouncer_mini::{DebounceEventResult, Debouncer, new_debouncer};
use crate::{Event, error::Error};
pub fn watch(
path: &PathBuf,
tx: Sender<Event>,
debounce_milliseconds: u64,
) -> Result<Debouncer<RecommendedWatcher>, Error> {
let parent = path
.parent()
.ok_or(Error::Watch("cannot watch without path".to_owned()))?
.to_owned();
let filename = path
.file_name()
.ok_or(Error::Watch(
"could not get filename part of path".to_owned(),
))?
.to_owned();
let mtime = Some(fs::metadata(path).and_then(|m| m.modified())?);
let last_mtime: Cell<Option<SystemTime>> = Cell::new(mtime);
let mtime_path = path.clone();
let mut debouncer = new_debouncer(
Duration::from_millis(debounce_milliseconds),
move |res: DebounceEventResult| match res {
Ok(events) => {
let dominated = events.iter().any(|e| e.path.file_name() == Some(&filename));
if !dominated {
return;
}
let mtime = fs::metadata(&mtime_path).and_then(|m| m.modified()).ok();
if mtime == last_mtime.get() {
return;
}
last_mtime.set(mtime);
log::warn!("watch mtime changed, Cmd::FileChanged");
if let Err(err) = tx.send(Event::FileChanged) {
log::error!("Failed to send Cmd::FileChanged: {err}");
}
}
Err(err) => {
log::error!("DebounceEventResult error: {err}");
}
},
)?;
log::info!("notify is watching {path:?}");
debouncer
.watcher()
.watch(&parent, RecursiveMode::NonRecursive)?;
Ok(debouncer)
}