What is notify-rs
-
notify-rs is a Rust crate that provides cross-platform file system event
notification.
It allows Rust applications to monitor changes to files/directories in a platform-independent way. This is particularly useful for applications that need to respond to changes in the file system, such as updating cached data, synchronizing files, or triggering specific actions when certain files are modified, created, or deleted.
RecommendedWatcher vs PollWatcher
| RecommendedWatcher | PollWatcher | |
|---|---|---|
| What | Implementation of Watcher trait provided by the notify crate | same |
| How | Watches inodes. Drawback on linux: on every file change, linux creates new inode. Hence we get 2 events write,Remove. Where remove is false positive. | Watches Paths(not inodes). This does not generate Remove event on file edit. |
RecommendedWatcher Code
-
https://github.com/notify-rs/notify/blob/main/examples/async_monitor.rs
fn main() {
let mut rt = tokio::runtime::new().unwrap();
let local = LocalSet::new();
local.block_on(&mut rt, async {
match do_main().await {
Ok (_o) => {
println!("Success");
}
Err (e) => {
println!("do_main failed");
}
}
});
}
pub async fn do_main() -> Result<(), String> {
match do_start().await {
Ok (join_handles) => {
for join in join_handles {
if let Err(e) = join.await {
println!("join failed {}", e);
}
}
}
Err(e) => {
return Err(str);
}
}
Ok(())
}
pub async fn do_start() -> Result<Vec<JoinHandles<()>>, ()> {
loop {
match Monitor::spawn_task().await {
Ok (h) => {
join_handles.push(h);
}
Err (e) => {
println!(e);
break;
}
}
break;
}
}
pub struct Monitor{}
impl Monitor {
pub async fn spawn_task () -> Result<tokio::task::JoinHandle<()>, Box<dyn std::error::Error> >{
let handle = tokio::spawn(async {
let Err (e) = Self::async_watch(path).await {
match e.kind {
notify::ErrorKind::Io(_) => {
prinlnt!("{} IO Error", e);
}
_ => {}
}
}
});
Ok(handle)
}
async fn async_watcher() -> notify::Result<(RecommendedWatcher, <Receivernotify::Result<Event>>)> {
let (mut tx, rx) = channel(1);
let watcher = RecommendedWatcher::new(
move |res| {
futures::executor::block_on(async {
tx.send(res).await.unwrap();
})
},
Config::default(),
)?;
Ok((watcher, rx))
}
async fn async_watch<P: AsRef<Path>>(path: P) -> notify::Result<()> {
let (mut watcher, mut rx) = async_watcher()?;
watcher.watch(path.as_ref(), RecursiveMode::Recursive)?;
while let Some(res) = rx.next().await {
match res {
Ok(event) => {
println!("changed: {:?}", event);
match event.kind {
notify::Eventkind::Remove(notify::event::Removekind::File) => {
// Rewatch
watcher.watch (path.as_ref(), RecursiveMode::Recursive)?;
},
_ => {}
}
},
Err(e) => println!("watch error: {:?}", e),
}
}
Ok(())
}
}
PollWatcher
-
https://github.com/notify-rs/notify/blob/main/examples/pollwatcher_scan.rs
fn main() {
let mut rt = tokio::runtime::new().unwrap();
let local = LocalSet::new();
local.block_on(&mut rt, async {
match async_watch(path).await {
Ok (_o) => {
println!("Success");
}
Err (e) => {
println!("do_main failed");
}
}
});
}
async fn async_watch(path: &str) -> notify::Result<()> {
enum Message {
Event(notify::Result<notify::Event>),
}
let (tx, rx):(async_channel::Sender<Message>, async_channel::Reciever<Message>) = async_channel::unbounded();
let tx_c = tx.clone();
let mut watcher = PollWatcher::new(
move |watch_event| {
tx_c.send(Message::Event(watch_event)).unwrap();
},
Config::default(),
)?;
watcher.watch(path.as_ref(), RecursiveMode::Recursive)?;
while let Ok(res) = rx.recv().await {
match res {
Message::Event(e) => println!("Watch event {e:?}"),
Message::Scan(e) => println!("Scan event {e:?}"),
}
}
Ok(())
}