// The `--reload` file watcher (← uvicorn's `--reload`), kept in a native-only file: it is backed by
// `@fs.Watcher`, which the async `fs` library provides only on native (inotify / kqueue / Windows) —
// there is no wasm or js file-watch backend. The rest of the process model (the graceful acceptor,
// `ShutdownHandle`) rides `@socket`, which compiles on every target, so it stays target-neutral.
///|
/// Watch `path` for source changes and fire `on_reload` on each batch of events
/// (← uvicorn's `--reload` file watcher). Backed by `@fs.Watcher`, which
/// debounces and reports child-file events, so a save to any file under `path`
/// triggers one reload. `on_reload` is where a supervisor re-execs the server;
/// wiring it to a `ShutdownHandle` turns a file save into a graceful restart.
/// Loops until its task is cancelled, always closing the watcher.
pub async fn reload_watch(path : String, on_reload : async () -> Unit) -> Unit {
let watcher = @fs.Watcher::Watcher(path, report_child_event=true)
defer watcher.close()
for ;; {
let events = watcher.wait()
if events.length() > 0 {
on_reload()
}
}
}
///|
/// The reload watcher fires on a genuine file change: write a file, start the
/// watcher over its directory, modify the file, and observe the callback run.
async test "reload watcher fires on a real file change" {
@async.with_task_group(g => {
let dir = @fs.tmpdir(prefix="mooncat-reload")
let file = "\{dir}/app.mbt"
@fs.write_file(file, b"one", create_mode=CreateOrTruncate)
let hits = Ref(0)
let task = g.spawn(() => reload_watch(dir, () => hits.val = hits.val + 1))
@async.sleep(200)
@fs.write_file(file, b"two", create_mode=CreateOrTruncate)
@async.sleep(500)
task.cancel()
assert_eq(hits.val >= 1, true)
@fs.rmdir(dir, recursive=true)
})
}