1use std::{future::Future, pin::pin};
3use tracing::trace;
4
5#[derive(Clone, Debug, Default)]
7#[non_exhaustive]
8pub struct NewtonRunner;
9
10impl NewtonRunner {
11 pub fn run_blocking_until_ctrl_c<F, E>(self, fut: F) -> Result<(), E>
13 where
14 F: Future<Output = Result<(), E>> + Send + 'static,
15 E: Send + Sync + From<std::io::Error> + 'static,
16 {
17 let tokio_runtime = tokio_runtime()?;
18 let handle = tokio_runtime.handle().clone();
19 let fut = tokio_runtime.handle().spawn_blocking(move || handle.block_on(fut));
20 tokio_runtime.block_on(run_until_ctrl_c(async move { fut.await.expect("Failed to join task") }))?;
21
22 std::thread::Builder::new()
26 .name("tokio-runtime-shutdown".to_string())
27 .spawn(move || drop(tokio_runtime))
28 .unwrap();
29
30 Ok(())
31 }
32}
33
34pub fn tokio_runtime() -> Result<tokio::runtime::Runtime, std::io::Error> {
37 tokio::runtime::Builder::new_multi_thread().enable_all().build()
38}
39
40async fn run_until_ctrl_c<F, E>(fut: F) -> Result<(), E>
44where
45 F: Future<Output = Result<(), E>>,
46 E: Send + Sync + 'static + From<std::io::Error>,
47{
48 let ctrl_c = tokio::signal::ctrl_c();
49
50 #[cfg(unix)]
51 {
52 let mut stream = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())?;
53 let sigterm = stream.recv();
54 let sigterm = pin!(sigterm);
55 let ctrl_c = pin!(ctrl_c);
56 let fut = pin!(fut);
57
58 tokio::select! {
59 _ = ctrl_c => {
60 trace!(target: "newton_prover::cli", "Received ctrl-c");
61 },
62 _ = sigterm => {
63 trace!(target: "newton_prover::cli", "Received SIGTERM");
64 },
65 res = fut => res?,
66 }
67 }
68
69 #[cfg(not(unix))]
70 {
71 let ctrl_c = pin!(ctrl_c);
72 let fut = pin!(fut);
73
74 tokio::select! {
75 _ = ctrl_c => {
76 trace!(target: "newton_prover::cli", "Received ctrl-c");
77 },
78 res = fut => res?,
79 }
80 }
81
82 Ok(())
83}