use anyhow::Result;
use tokio::task::JoinSet;
use tokio_listener::Listener;
use crate::tenx_programmer::TenXProgrammer;
pub mod freezer;
pub mod state_of_decay;
pub use freezer::{Freezer, Variant};
pub use state_of_decay::{Decay, StateOfDecay};
pub struct Body(pub Freezer);
impl Body {
pub fn new(inner: Freezer) -> Self {
Self(inner)
}
async fn start_server(self) -> Result<()> {
tracing::info!("starting iocaine");
let mut servers = JoinSet::new();
let mut system_opts = tokio_listener::SystemOptions::default();
system_opts.sleep_on_errors = true;
for (_name, server) in self.0.servers {
let mut opts = tokio_listener::UserOptions::default();
opts.unix_listen_unlink = true;
opts.unix_listen_chmod = server.unix_socket_access;
let listener = Listener::bind(&server.bind, &system_opts, &opts).await?;
match server.variant {
Variant::Prometheus(srv) => {
servers.spawn(async { Ok(srv.serve(listener).await?) });
}
Variant::Http(srv) => {
servers.spawn(async { srv.serve(listener).await });
}
Variant::HaproxySPOA(srv) => {
servers.spawn(async move { srv.serve(listener).await });
}
}
}
#[cfg(target_os = "linux")]
let _ = sd_notify::notify(false, &[sd_notify::NotifyState::Ready]);
tracing::info!("iocaine ready");
let _ = servers.join_all().await;
Ok(())
}
pub async fn run(self) -> Result<()> {
self.start_server().await
}
}
pub async fn shutdown_signal(metrics: Option<TenXProgrammer>) {
let ctrl_c = async {
tokio::signal::ctrl_c()
.await
.expect("failed to install Ctrl+C handler");
};
let terminate = async {
tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
.expect("failed to install signal handler")
.recv()
.await;
};
tokio::select! {
() = ctrl_c => {},
() = terminate => {},
}
#[cfg(target_os = "linux")]
let _ = sd_notify::notify(false, &[sd_notify::NotifyState::Stopping]);
if let Some(metrics) = metrics {
metrics.abort();
let _ = metrics.persist().inspect_err(|error| {
tracing::error!({ error = format!("{error}") }, "error persisting metrics");
});
}
}