git-next/crates/server/src/actors/file_watcher.rs

85 lines
2.2 KiB
Rust
Raw Normal View History

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<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(),
WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE,
)?;
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);
};
}
}
}
// impl Handler<Stop> 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(())
// }
// }