// use actix::prelude::*; use actix::Recipient; use anyhow::{Context, Result}; use notify::{event::ModifyKind, Watcher}; use tracing::{error, info}; use std::{ path::PathBuf, sync::{ atomic::{AtomicBool, Ordering}, Arc, }, time::Duration, }; #[derive(Debug, Message)] #[rtype(result = "()")] pub struct FileUpdated; #[derive(Debug, thiserror::Error)] pub enum Error { #[error("io")] Io(#[from] std::io::Error), } pub fn watch_file(path: PathBuf, recipient: Recipient) -> Result> { let (tx, rx) = std::sync::mpsc::channel(); let shutdown = Arc::new(AtomicBool::default()); let mut handler = notify::recommended_watcher(tx).context("file watcher")?; handler .watch(&path, notify::RecursiveMode::NonRecursive) .with_context(|| format!("Watching: {path:?}"))?; let thread_shutdown = shutdown.clone(); actix_rt::task::spawn_blocking(move || { loop { if thread_shutdown.load(Ordering::Relaxed) { drop(handler); break; } for result in rx.try_iter() { match result { Ok(event) => match event.kind { notify::EventKind::Modify(ModifyKind::Data(_)) => { info!("File modified"); recipient.do_send(FileUpdated); break; } notify::EventKind::Modify(_) | notify::EventKind::Create(_) | notify::EventKind::Remove(_) | notify::EventKind::Any | notify::EventKind::Access(_) | notify::EventKind::Other => { /* do nothing */ } }, Err(err) => { error!(?err, "Watching file: {path:?}"); } } } std::thread::sleep(Duration::from_millis(1000)); } }); Ok(shutdown) }