use std::{
collections::HashMap,
path::Path,
sync::{mpsc::channel, Arc, Mutex},
thread,
time::Duration,
};
use chrono::Utc;
use notify::{EventKind, RecursiveMode, Watcher};
use simple_websockets::{Event, Message, Responder};
use crate::Port;
const MIN_RECOMPILE_INTERVAL: u32 = 1000;
const FILE_SAVE_WAIT: u64 = 300;
pub fn watch<F>(router: F, watched_folders: &[&str], port: Port)
where
F: Fn(),
{
let event_hub = unwrap!(
simple_websockets::launch(port),
err: "Failed to initialize websockets on port {} `{err:?}`",
port
);
let clients = Arc::new(Mutex::new(HashMap::<u64, Responder>::new()));
let last_server_start = Utc::now().timestamp();
let clients_clone = clients.clone();
thread::spawn(move || loop {
let mut clients = clients_clone.lock().unwrap();
for event in event_hub.drain() {
match event {
Event::Connect(id, responder) => {
responder.send(Message::Text(last_server_start.to_string()));
clients.insert(id, responder);
}
Event::Disconnect(id) => {
clients.remove(&id);
}
_ => (),
}
}
});
let (tx, rx) = channel();
let mut watcher =
unwrap!(notify::recommended_watcher(tx), err: "Could not create file watcher `{err:?}`");
for folder in watched_folders {
unwrap!(
watcher.watch(Path::new(folder), RecursiveMode::Recursive),
err: "Could not watch folder '{}' `{err:?}`", folder
)
}
let mut last_compile = Utc::now().timestamp();
loop {
let Ok(Ok(event)) = rx.recv() else {
continue;
};
if !matches!(
event.kind,
EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_)
) {
continue;
}
let now = Utc::now().timestamp_millis();
if last_compile + (MIN_RECOMPILE_INTERVAL as i64) > now {
continue;
}
last_compile = now;
thread::sleep(Duration::from_millis(FILE_SAVE_WAIT));
router();
let clients = clients.lock().unwrap();
for (_id, client) in clients.iter() {
client.send(Message::Text("reload".to_string()));
}
}
}