2024-05-07 19:32:15 +01:00
|
|
|
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);
|
|
|
|
|
2024-05-15 21:01:19 +01:00
|
|
|
#[derive(Debug, Clone, Message)]
|
|
|
|
#[rtype(result = "()")]
|
2024-05-07 19:32:15 +01:00
|
|
|
pub struct WatchFile;
|
|
|
|
|
2024-05-15 21:01:19 +01:00
|
|
|
#[derive(Debug, Message)]
|
|
|
|
#[rtype(result = "()")]
|
2024-05-07 19:32:15 +01:00
|
|
|
pub struct FileUpdated;
|
|
|
|
|
2024-06-03 20:34:01 +01:00
|
|
|
#[derive(Debug, thiserror::Error)]
|
2024-05-07 19:32:15 +01:00
|
|
|
pub enum Error {
|
2024-06-03 20:34:01 +01:00
|
|
|
#[error("io")]
|
|
|
|
Io(#[from] std::io::Error),
|
2024-05-07 19:32:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct FileWatcher {
|
|
|
|
path: PathBuf,
|
|
|
|
inotify: Inotify,
|
|
|
|
recipient: Recipient<FileUpdated>,
|
|
|
|
run_interval: Option<SpawnHandle>,
|
|
|
|
}
|
|
|
|
impl FileWatcher {
|
|
|
|
pub fn new(path: PathBuf, recipient: Recipient<FileUpdated>) -> Result<Self, Error> {
|
|
|
|
let inotify = Inotify::init()?;
|
|
|
|
inotify.watches().add(
|
|
|
|
path.clone(),
|
2024-05-23 09:01:57 +01:00
|
|
|
WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE | WatchMask::ATTRIB,
|
2024-05-07 19:32:15 +01:00
|
|
|
)?;
|
|
|
|
Ok(Self {
|
|
|
|
path,
|
|
|
|
inotify,
|
|
|
|
recipient,
|
|
|
|
run_interval: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Actor for FileWatcher {
|
|
|
|
type Context = Context<Self>;
|
|
|
|
|
|
|
|
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<WatchFile> 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);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|