use actix::prelude::*; use actix::Recipient; use inotify::{EventMask, Inotify, WatchMask}; use std::{path::PathBuf, time::Duration}; use tracing::{debug, info}; const CHECK_INTERVAL: Duration = Duration::from_secs(1); #[derive(Debug, Clone)] pub struct WatchFile; impl Message for WatchFile { type Result = (); } #[derive(Debug)] pub struct FileUpdated; impl Message for FileUpdated { type Result = (); } #[derive(Debug, derive_more::From, derive_more::Display)] pub enum Error { Io(std::io::Error), } impl std::error::Error for Error {} pub struct FileWatcher { path: PathBuf, inotify: Inotify, recipient: Recipient, run_interval: Option, } impl FileWatcher { pub fn new(path: PathBuf, recipient: Recipient) -> Result { let inotify = Inotify::init()?; inotify.watches().add( path.clone(), WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE, )?; Ok(Self { path, inotify, recipient, run_interval: None, }) } } impl Actor for FileWatcher { type Context = Context; fn started(&mut self, ctx: &mut Self::Context) { info!("Starting file watcher actor"); self.run_interval .replace(ctx.run_interval(CHECK_INTERVAL, |_act, ctx| { ctx.notify(WatchFile); })); } } impl Handler for FileWatcher { type Result = (); fn handle(&mut self, _msg: WatchFile, _ctx: &mut Self::Context) -> Self::Result { debug!("Watching {} for activity...", self.path.display()); let mut buffer = [0u8; 4096]; if let Ok(mut events) = self.inotify.read_events(&mut buffer) { if events.any(|event| event.mask.contains(EventMask::MODIFY)) { info!("File modified"); self.recipient.do_send(FileUpdated); }; } } } // impl Handler for FileWatcher { // type Result = anyhow::Result<()>; // // fn handle(&mut self, _msg: Stop, ctx: &mut Self::Context) -> Self::Result { // warn!("Stopping file watcher actor"); // self.run_interval.take(); // ctx.stop(); // Ok(()) // } // }