1use cordis::Context;
4use cordis_loader::{Loader, LoaderConfig};
5use std::path::Path;
6use std::sync::Arc;
7
8pub const EXIT_RESTART: i32 = 51;
10pub const EXIT_QUIT: i32 = 52;
12
13pub struct WorkerHandle {
16 inner: Arc<WorkerInner>,
17}
18
19impl WorkerHandle {
20 pub fn restart(&self) -> ! {
22 self.inner.teardown();
23 std::process::exit(EXIT_RESTART);
24 }
25
26 pub fn shutdown(&self) -> ! {
28 self.inner.teardown();
29 std::process::exit(EXIT_QUIT);
30 }
31}
32
33struct WorkerInner {
35 root: Context,
36 loader: Option<Loader>,
37}
38
39impl WorkerInner {
40 fn teardown(&self) {
41 if let Some(loader) = &self.loader {
42 let _ = loader.dispose();
43 }
44 let _ = self.root.fiber().and_then(|fiber| fiber.dispose());
45 }
46}
47
48pub fn run(config_path: &Path) -> ! {
52 let root = Context::new();
53 let loader = match Loader::open(&root, LoaderConfig::new(config_path)) {
54 Ok(loader) => loader,
55 Err(error) => {
56 eprintln!(
57 "cordis: failed to start from {}: {error}",
58 config_path.display()
59 );
60 std::process::exit(EXIT_QUIT);
61 }
62 };
63 let inner = Arc::new(WorkerInner {
64 root: root.clone(),
65 loader: Some(loader.clone()),
66 });
67
68 let handle = Arc::new(WorkerHandle {
69 inner: Arc::clone(&inner),
70 });
71 if let Err(error) = root.provide_arc("worker", handle) {
72 eprintln!("cordis: could not expose the worker service: {error}");
73 }
74
75 let signal_inner = Arc::clone(&inner);
76 if ctrlc::set_handler(move || {
77 eprintln!("cordis: signal received, shutting down");
78 signal_inner.teardown();
79 std::process::exit(EXIT_QUIT);
80 })
81 .is_err()
82 {
83 eprintln!("cordis: could not install signal handlers");
84 }
85
86 match loader.watch() {
87 Ok(_watcher) => {}
88 Err(error) => eprintln!(
89 "cordis: config hot reload disabled ({error}); restart manually to apply changes"
90 ),
91 }
92
93 eprintln!(
94 "cordis: worker ready ({} entries, config: {})",
95 loader.tree().entries().len(),
96 config_path.display()
97 );
98
99 loop {
102 std::thread::park();
103 }
104}