1use tokio::signal::unix;
4use tokio::signal::unix::SignalKind;
5use tokio::task::JoinHandle;
6use tokio_util::sync::{CancellationToken, WaitForCancellationFuture};
7
8#[derive(Default)]
9pub struct Controller {
10 token: CancellationToken,
11}
12
13impl Clone for Controller {
14 fn clone(&self) -> Self {
15 Self {
16 token: self.token.child_token(),
17 }
18 }
19}
20
21impl Controller {
22 #[must_use]
24 pub fn new() -> Self {
25 Self::default()
26 }
27
28 pub fn shutdown(&self) {
30 self.token.cancel();
31 }
32
33 pub fn wait_for_shutdown(&self) -> WaitForCancellationFuture<'_> {
35 self.token.cancelled()
36 }
37
38 pub fn spawn_handler(self) -> std::io::Result<JoinHandle<()>> {
44 let mut qt = unix::signal(SignalKind::quit())?;
45 let mut tm = unix::signal(SignalKind::terminate())?;
46
47 let handle = tokio::spawn(async move {
48 tokio::select! {
49 _ = qt.recv() => {
50 tracing::debug!("received SIGQUIT signal");
51 },
52 _ = tm.recv() => {
53 tracing::debug!("received SIGTERM signal");
54 }
55 res = tokio::signal::ctrl_c() => {
56 match res {
57 Ok(_) => tracing::debug!("received ctrl-c shutdown request"),
58 Err(err) => {
59 let report = crate::report!(err);
60 tracing::error!("{report:?}");
61 }
62 }
63 }
64 }
65 tracing::trace!("sending shutdown signal");
66 self.shutdown();
67 tracing::trace!("shutdown complete");
68 });
69 Ok(handle)
70 }
71}