use cordis::Context;
use cordis_loader::{Loader, LoaderConfig};
use std::path::Path;
use std::sync::Arc;
pub const EXIT_RESTART: i32 = 51;
pub const EXIT_QUIT: i32 = 52;
pub struct WorkerHandle {
inner: Arc<WorkerInner>,
}
impl WorkerHandle {
pub fn restart(&self) -> ! {
self.inner.teardown();
std::process::exit(EXIT_RESTART);
}
pub fn shutdown(&self) -> ! {
self.inner.teardown();
std::process::exit(EXIT_QUIT);
}
}
struct WorkerInner {
root: Context,
loader: Option<Loader>,
}
impl WorkerInner {
fn teardown(&self) {
if let Some(loader) = &self.loader {
let _ = loader.dispose();
}
let _ = self.root.fiber().and_then(|fiber| fiber.dispose());
}
}
pub fn run(config_path: &Path) -> ! {
let root = Context::new();
let loader = match Loader::open(&root, LoaderConfig::new(config_path)) {
Ok(loader) => loader,
Err(error) => {
eprintln!(
"cordis: failed to start from {}: {error}",
config_path.display()
);
std::process::exit(EXIT_QUIT);
}
};
let inner = Arc::new(WorkerInner {
root: root.clone(),
loader: Some(loader.clone()),
});
let handle = Arc::new(WorkerHandle {
inner: Arc::clone(&inner),
});
if let Err(error) = root.provide_arc("worker", handle) {
eprintln!("cordis: could not expose the worker service: {error}");
}
let signal_inner = Arc::clone(&inner);
if ctrlc::set_handler(move || {
eprintln!("cordis: signal received, shutting down");
signal_inner.teardown();
std::process::exit(EXIT_QUIT);
})
.is_err()
{
eprintln!("cordis: could not install signal handlers");
}
match loader.watch() {
Ok(_watcher) => {}
Err(error) => eprintln!(
"cordis: config hot reload disabled ({error}); restart manually to apply changes"
),
}
eprintln!(
"cordis: worker ready ({} entries, config: {})",
loader.tree().entries().len(),
config_path.display()
);
loop {
std::thread::park();
}
}