fips 1.0.1

A powerful mock server supported by a plugin system
Documentation
use std::alloc::System;

#[global_allocator]
static ALLOCATOR: System = System;

use clap::Parser;
use configuration::configuration::Config;
use std::fs::File;
use std::sync::Arc;
use tokio::runtime::Runtime;

mod backend;
mod configuration;
mod fips;
mod plugin_registry;
mod terminal_ui;
mod utility;

use crate::configuration::ruleset::RuleSet;
use crate::utility::log::Loggable;
use crate::utility::options::CliOptions;

use tokio::sync::Mutex as AsyncMutex;

#[cfg(feature = "logging")]
mod logging;

#[cfg(feature = "ui")]
mod frontend;

type LogFunction = Box<dyn Fn(&Loggable) + Send + Sync>;

pub struct PaintLogsCallbacks(LogFunction);

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cli_options = CliOptions::parse();

    #[cfg(feature = "logging")]
    {
        logging::init()?;
        log::info!("Starting FIPS on port {} with config paths: {:?}", cli_options.port, cli_options.config);
        std::panic::set_hook({
            Box::new(|e| {
                log::error!("Panic: {}", e);
            })
        });
    }

    if cli_options.write_schema {
        let schema = schemars::schema_for!(Vec<RuleSet>);
        serde_json::to_writer(&File::create("fips-schema.json")?, &schema)?;
        //exit early
        return Ok(());
    };

    //TODO: get rid of duplication caused by introduction of async mutex
    let async_configuration = Arc::new(AsyncMutex::new(
        Config::load(&cli_options.config).unwrap_or_default(),
    ));

    let (_state, _app, logging) = {
        #[cfg(feature = "ui")]
        let (state, app, logging) = {
            frontend::setup(
                Arc::clone(&async_configuration),
                cli_options.clone(),
            )
            .await
        };
        #[cfg(not(feature = "ui"))]
        let (state, app, logging) = { backend::setup() };
        (state, app, logging)
    };

    let addr = ([127, 0, 0, 1], cli_options.port).into();
    let runtime = Runtime::new().unwrap();
    let _guard = runtime.enter();

    let _rt_handle =
        backend::spawn_backend(&async_configuration, &addr, &logging);

    #[cfg(feature = "ui")]
    {
        frontend::spawn_frontend(_app, runtime).await?;
    }

    #[cfg(not(feature = "ui"))]
    {
        println!("FIPS server running on http://127.0.0.1:{}", cli_options.port);
        println!("Config paths: {:?}", cli_options.config);
        _rt_handle.await?.unwrap();
    }

    Ok(())
}