parent
22faa851dc
commit
a56c6df3f1
5 changed files with 45 additions and 65 deletions
|
@ -91,7 +91,7 @@ thiserror = "1.0"
|
||||||
pike = "0.1"
|
pike = "0.1"
|
||||||
|
|
||||||
# file watcher
|
# file watcher
|
||||||
inotify = "0.10"
|
notify = "6.1"
|
||||||
|
|
||||||
# Actors
|
# Actors
|
||||||
actix = "0.13"
|
actix = "0.13"
|
||||||
|
|
|
@ -65,7 +65,7 @@ bytes = { workspace = true }
|
||||||
warp = { workspace = true }
|
warp = { workspace = true }
|
||||||
|
|
||||||
# file watcher (linux)
|
# file watcher (linux)
|
||||||
inotify = { workspace = true }
|
notify = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# Testing
|
# Testing
|
||||||
|
|
|
@ -2,15 +2,13 @@
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
use actix::Recipient;
|
use actix::Recipient;
|
||||||
use inotify::{EventMask, Inotify, WatchMask};
|
use notify::event::ModifyKind;
|
||||||
|
use notify::Watcher;
|
||||||
|
use tracing::error;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
use std::{path::PathBuf, time::Duration};
|
use std::path::PathBuf;
|
||||||
|
use std::time::Duration;
|
||||||
const CHECK_INTERVAL: Duration = Duration::from_secs(1);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Message)]
|
|
||||||
#[rtype(result = "()")]
|
|
||||||
pub struct WatchFile;
|
|
||||||
|
|
||||||
#[derive(Debug, Message)]
|
#[derive(Debug, Message)]
|
||||||
#[rtype(result = "()")]
|
#[rtype(result = "()")]
|
||||||
|
@ -21,50 +19,40 @@ pub enum Error {
|
||||||
#[error("io")]
|
#[error("io")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
}
|
}
|
||||||
|
pub async fn watch_file(path: PathBuf, recipient: Recipient<FileUpdated>) {
|
||||||
|
let (tx, rx) = std::sync::mpsc::channel();
|
||||||
|
|
||||||
pub struct FileWatcher {
|
#[allow(clippy::expect_used)]
|
||||||
inotify: Inotify,
|
let mut handler = notify::recommended_watcher(tx).expect("file watcher");
|
||||||
recipient: Recipient<FileUpdated>,
|
#[allow(clippy::expect_used)]
|
||||||
run_interval: Option<SpawnHandle>,
|
handler
|
||||||
}
|
.watch(&path, notify::RecursiveMode::NonRecursive)
|
||||||
impl FileWatcher {
|
.expect("watch file");
|
||||||
pub fn new(path: PathBuf, recipient: Recipient<FileUpdated>) -> Result<Self, Error> {
|
info!("Watching: {:?}", path);
|
||||||
let inotify = Inotify::init()?;
|
async move {
|
||||||
inotify.watches().add(
|
loop {
|
||||||
path,
|
for result in rx.try_iter() {
|
||||||
WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE | WatchMask::ATTRIB,
|
match result {
|
||||||
)?;
|
Ok(event) => match event.kind {
|
||||||
Ok(Self {
|
notify::EventKind::Modify(ModifyKind::Data(_)) => {
|
||||||
inotify,
|
|
||||||
recipient,
|
|
||||||
run_interval: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Actor for FileWatcher {
|
|
||||||
type Context = Context<Self>;
|
|
||||||
|
|
||||||
fn started(&mut self, ctx: &mut Self::Context) {
|
|
||||||
tracing::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 {
|
|
||||||
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) || event.mask.contains(EventMask::ATTRIB)
|
|
||||||
}) {
|
|
||||||
tracing::info!("File modified");
|
tracing::info!("File modified");
|
||||||
self.recipient.do_send(FileUpdated);
|
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:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
actix_rt::time::sleep(Duration::from_millis(1000)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
|
@ -243,6 +243,5 @@ impl ServerActor {
|
||||||
}
|
}
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
_ctx.address().do_send(msg);
|
_ctx.address().do_send(msg);
|
||||||
tracing::info!("sent");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,12 @@ mod tests;
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
use crate::file_watcher::{FileUpdated, FileWatcher};
|
use crate::file_watcher::{watch_file, FileUpdated};
|
||||||
use actor::ServerActor;
|
use actor::ServerActor;
|
||||||
use git_next_core::git::RepositoryFactory;
|
use git_next_core::git::RepositoryFactory;
|
||||||
|
|
||||||
use kxio::{fs::FileSystem, network::Network};
|
use kxio::{fs::FileSystem, network::Network};
|
||||||
use tracing::{error, info, level_filters::LevelFilter};
|
use tracing::{info, level_filters::LevelFilter};
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -45,20 +45,13 @@ pub fn start(
|
||||||
) {
|
) {
|
||||||
init_logging();
|
init_logging();
|
||||||
|
|
||||||
info!("Starting Server...");
|
|
||||||
let execution = async move {
|
let execution = async move {
|
||||||
|
info!("Starting Server...");
|
||||||
let server = ServerActor::new(fs.clone(), net.clone(), repo, sleep_duration).start();
|
let server = ServerActor::new(fs.clone(), net.clone(), repo, sleep_duration).start();
|
||||||
server.do_send(FileUpdated);
|
server.do_send(FileUpdated);
|
||||||
|
|
||||||
info!("Starting File Watcher...");
|
info!("Starting File Watcher...");
|
||||||
let fw = match FileWatcher::new("git-next-server.toml".into(), server.clone().recipient()) {
|
watch_file("git-next-server.toml".into(), server.clone().recipient()).await;
|
||||||
Ok(fw) => fw,
|
|
||||||
Err(err) => {
|
|
||||||
error!(?err, "Failed to start file watcher");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
fw.start();
|
|
||||||
|
|
||||||
info!("Server running - Press Ctrl-C to stop...");
|
info!("Server running - Press Ctrl-C to stop...");
|
||||||
let _ = actix_rt::signal::ctrl_c().await;
|
let _ = actix_rt::signal::ctrl_c().await;
|
||||||
|
|
Loading…
Reference in a new issue