69 lines
2.4 KiB
Rust
69 lines
2.4 KiB
Rust
|
|
use std::sync::Arc;
|
|
use futures::{Future, StreamExt};
|
|
use tokio::fs::File;
|
|
use tokio::sync::RwLock;
|
|
|
|
use inotify::{Inotify, WatchMask};
|
|
|
|
pub async fn load<F, R, T>(path: &str, f: F) -> Result<Arc<RwLock<T>>, tokio::io::Error>
|
|
where
|
|
F: Fn(File) -> R + Send + Sync + 'static,
|
|
R: Future<Output = T> + Send,
|
|
T: Send + Sync + 'static,
|
|
{
|
|
let f = Arc::new(f);
|
|
let t = f(File::open(path).await?).await;
|
|
let lock = Arc::new(RwLock::new(t));
|
|
let lock_ = lock.clone();
|
|
let path = std::env::current_dir()
|
|
.unwrap()
|
|
.join(path).clone();
|
|
let dir = path.parent().unwrap().to_path_buf();
|
|
|
|
let path = Arc::new(RwLock::new(path));
|
|
let dir = Arc::new(RwLock::new(dir));
|
|
|
|
tokio::spawn(async move {
|
|
let inotify = Inotify::init()
|
|
.unwrap();
|
|
inotify.watches().add(&*dir.read().await, WatchMask::MODIFY | WatchMask::CREATE | WatchMask::MOVED_TO)
|
|
.unwrap();
|
|
tracing::debug!("Watching directory {:?}", &dir);
|
|
inotify.into_event_stream([0; 1024])
|
|
.unwrap()
|
|
.for_each(|result| {
|
|
let path = path.clone();
|
|
let dir = dir.clone();
|
|
let f = f.clone();
|
|
let lock = lock_.clone();
|
|
async move {
|
|
match result {
|
|
Ok(e) => {
|
|
if let Some(name) = e.name {
|
|
let dir = dir.read().await;
|
|
let path = path.read().await;
|
|
if dir.join(name) == *path {
|
|
match File::open(&*path).await {
|
|
Ok(file) => {
|
|
let t = f(file).await;
|
|
*lock.write().await = t;
|
|
tracing::info!("reloaded {}", path.display());
|
|
}
|
|
Err(e) =>
|
|
tracing::error!("error opening {}: {}", path.display(), e),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Err(e) => {
|
|
tracing::error!("inotify: {}", e);
|
|
}
|
|
}
|
|
}
|
|
}).await;
|
|
});
|
|
|
|
Ok(lock)
|
|
}
|