1use futures::{
20	future::{self, BoxFuture, FutureExt},
21	pin_mut, select, Future,
22};
23
24use sc_service::Error as ServiceError;
25
26pub struct Signals(BoxFuture<'static, ()>);
30
31impl Signals {
32	pub fn future(self) -> BoxFuture<'static, ()> {
34		self.0
35	}
36
37	#[cfg(target_family = "unix")]
41	pub fn capture() -> std::result::Result<Self, ServiceError> {
42		use tokio::signal::unix::{signal, SignalKind};
43
44		let mut stream_int = signal(SignalKind::interrupt()).map_err(ServiceError::Io)?;
45		let mut stream_term = signal(SignalKind::terminate()).map_err(ServiceError::Io)?;
46
47		Ok(Signals(
48			async move {
49				future::select(stream_int.recv().boxed(), stream_term.recv().boxed()).await;
50			}
51			.boxed(),
52		))
53	}
54
55	#[cfg(not(unix))]
59	pub fn capture() -> Result<Self, ServiceError> {
60		use tokio::signal::ctrl_c;
61
62		Ok(Signals(
63			async move {
64				let _ = ctrl_c().await;
65			}
66			.boxed(),
67		))
68	}
69
70	pub fn dummy() -> Self {
72		Self(future::pending().boxed())
73	}
74
75	pub async fn run_until_signal<F, E>(self, func: F) -> Result<(), E>
77	where
78		F: Future<Output = Result<(), E>> + future::FusedFuture,
79		E: std::error::Error + Send + Sync + 'static,
80	{
81		let signals = self.future().fuse();
82
83		pin_mut!(func, signals);
84
85		select! {
86			_ = signals => {},
87			res = func => res?,
88		}
89
90		Ok(())
91	}
92
93	pub async fn try_until_signal<F, T>(self, func: F) -> Result<T, ()>
95	where
96		F: Future<Output = T> + future::FusedFuture,
97	{
98		let signals = self.future().fuse();
99
100		pin_mut!(func, signals);
101
102		select! {
103			s = signals => Err(s),
104			res = func => Ok(res),
105		}
106	}
107}