iocaine 3.4.0

The deadliest poison known to AI
// SPDX-FileCopyrightText: Gergely Nagy
// SPDX-FileContributor: Gergely Nagy
//
// SPDX-License-Identifier: MIT

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");
        });
    }
}