iocaine 3.4.0

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

#![allow(clippy::result_large_err)]

use figment::{
    Error, Metadata, Profile, Provider, Source, error,
    value::{Dict, Map},
};
use kdl::KdlDocument;
use std::fs;
use std::path::PathBuf;

mod format;
mod parse;
use parse::ParseExt;
mod traits;
use traits::KdlNodeExt;

use iocaine_powder::bullshit::SquashFS;

#[derive(Default)]
pub struct Cuddles {
    file: Option<PathBuf>,
}

struct Snuggles(KdlDocument);
impl From<KdlDocument> for Snuggles {
    fn from(k: KdlDocument) -> Self {
        Self(k)
    }
}

impl Provider for Cuddles {
    fn metadata(&self) -> Metadata {
        Metadata::named("KDL file").source(
            self.file
                .clone()
                .map_or_else(|| Source::Custom("default".into()), Source::File),
        )
    }
    fn data(&self) -> Result<Map<Profile, Dict>, Error> {
        let data = match &self.file {
            Some(f) => fs::read_to_string(f).map_err(|e| Error::from(format!("{e}")))?,
            None => match SquashFS::get("/defaults/config.kdl") {
                Some(v) => String::from_utf8_lossy(&v).to_string(),
                None => return Err(Error::from("Unable to find default config file")),
            },
        };
        let doc: Snuggles = data
            .parse::<KdlDocument>()
            .map_err(|e| Error::from(format!("{e}")))?
            .into();

        let map = doc.parse()?;

        match &self.profile() {
            Some(profile) => Ok(profile.collect(map)),
            None => Ok(figment::Profile::Default.collect(map)),
        }
    }
}

impl Cuddles {
    pub fn file(path: impl Into<PathBuf>) -> Self {
        Self {
            file: Some(path.into()),
        }
    }
}

impl Snuggles {
    pub fn parse(&self) -> Result<Dict, Error> {
        let mut dict = Dict::new();
        let mut servers = Dict::new();
        let mut handlers = Dict::new();

        for node in self.0.nodes() {
            match node.name().value() {
                "initial-seed" | "initial-seed-file" | "instance-id" | "state-directory" => {
                    let value = node
                        .assert_no_children()?
                        .assert_single_argument()?
                        .get_first_string_argument()?;
                    dict.insert(node.name().value().into(), value.into());
                }
                "http-server" => {
                    let (name, server) = node.parse_request_server("http")?;
                    servers.insert(name, server);
                }
                "haproxy-spoa-server" => {
                    let (name, server) = node.parse_request_server("haproxy-spoa")?;
                    servers.insert(name, server);
                }
                "prometheus-server" => {
                    let (name, server) = node.parse_prometheus_server()?;
                    servers.insert(name, server);
                }
                "declare-handler" => {
                    let (name, handler) = node.parse_declare_handler()?;
                    handlers.insert(name.into(), handler.into());
                }
                "firewall" => {
                    dict.insert("firewall".into(), node.parse_firewall()?.into());
                }
                name => {
                    let kind = error::Kind::Unsupported(error::Actual::Str(name.to_owned()));
                    return Err(Error::from(kind));
                }
            }
        }

        dict.insert("server".into(), servers.into());
        dict.insert("handler".into(), handlers.into());

        Ok(dict)
    }
}