iocaine 3.0.0

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

#[cfg(all(not(target_env = "musl"), feature = "jemalloc"))]
#[global_allocator]
static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;

use anyhow::Result;
use clap::{Parser, Subcommand};

use iocaine::morgue::Body;

mod config;
use config::Config;
mod commands;
use commands::show::{self, ShowCommands};
use commands::tests::{self, TestCommands};

#[derive(Debug, Parser, Default)]
#[command(version, about)]
pub struct Args {
    /// Path to load configuration from. Can be repeated.
    #[arg(short = 'c', long = "config-path")]
    pub config_paths: Vec<String>,

    #[command(subcommand)]
    command: Option<Commands>,
}

#[derive(Debug, Subcommand)]
enum Commands {
    /// Start the iocaine server. This is the default, if no command is specified.
    #[command(bin_name = "iocaine start")]
    Start,
    /// Run tests against the request handler.
    #[command(bin_name = "iocaine test")]
    Test {
        #[command(subcommand)]
        command: Option<TestCommands>,
    },
    /// Show something about iocaine (its configuration, for example), then exit.
    #[command(bin_name = "iocaine show")]
    Show {
        #[command(subcommand)]
        command: ShowCommands,
    },
}

#[tokio::main]
async fn main() -> Result<()> {
    #[cfg(all(feature = "tokio-console", not(tokio_unstable)))]
    compile_error!(
        "`tokio-console` requires manually enabling the `--cfg tokio_unstable` rust flag during compilation!"
    );

    #[cfg(all(feature = "tokio-console", tokio_unstable))]
    console_subscriber::init();

    #[cfg(not(all(feature = "tokio-console", tokio_unstable)))]
    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn")),
        )
        .with_writer(std::io::stderr)
        .init();

    let args = Args::parse();
    let command = args.command.unwrap_or(Commands::Start);

    let config = Config::load(&args.config_paths).unwrap_or_else(|err| panic!("{}", err));

    match command {
        Commands::Start => {
            let app = Body::new(config.try_into()?)?;
            app.run().await?;
        }
        Commands::Test { command } => tests::run(&config, command.unwrap_or_default())?,
        Commands::Show { command } => show::run(config, command)?,
    }

    Ok(())
}