iocaine 3.4.0

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

use figment::value::Value;
use kdl::{KdlDocument, KdlEntry, KdlNode};

use crate::dominatrix::{Config, Firewall, Handler, Server, Variant};

impl From<Config> for KdlDocument {
    fn from(config: Config) -> Self {
        let mut doc = Self::new();
        let nodes = doc.nodes_mut();

        nodes.push(config.initial_seed.to_kdl_node("initial-seed"));
        nodes.push(
            config
                .state_directory
                .display()
                .to_string()
                .to_kdl_node("state-directory"),
        );
        if let Some(id) = config.instance_id {
            nodes.push(id.to_kdl_node("instance-id"));
        }

        for (name, server) in &config.servers {
            nodes.push(server.to_kdl_node(name));
        }

        for (name, handler) in &config.handlers {
            nodes.push(handler.to_kdl_node(name));
        }

        if let Some(firewall) = config.firewall {
            nodes.push(firewall.to_kdl_node("firewall"));
        }

        doc
    }
}

trait KdlNodeWriteExt {
    fn to_kdl_node(&self, name: &str) -> KdlNode;
}

impl KdlNodeWriteExt for String {
    fn to_kdl_node(&self, name: &str) -> KdlNode {
        let mut node = KdlNode::new(name);
        node.push(KdlEntry::new(self.to_owned()));

        node
    }
}

impl KdlNodeWriteExt for Server {
    fn to_kdl_node(&self, server_name: &str) -> KdlNode {
        let (name, prefix) = match &self.variant {
            Variant::Http(_) => ("http-server", "http:"),
            Variant::HaproxySPOA(_) => ("haproxy-spoa-server", "haproxy-spoa:"),
            Variant::Prometheus(_) => ("prometheus-server", "prometheus:"),
        };
        let mut node = KdlNode::new(name);
        node.push(KdlEntry::new(
            server_name.strip_prefix(prefix).unwrap_or(server_name),
        ));

        let children = node.ensure_children();
        let child_nodes = children.nodes_mut();

        let mut bind = KdlNode::new("bind");
        bind.push(KdlEntry::new(self.bind.to_string()));
        if let Some(socket_access) = self.unix_socket_access {
            bind.insert("unix-socket-access", socket_access.to_string());
        }
        child_nodes.push(bind);

        match &self.variant {
            Variant::Http(rq) | Variant::HaproxySPOA(rq) => {
                if let Some(seed) = &rq.initial_seed {
                    child_nodes.push(seed.to_kdl_node("initial-seed"));
                }

                let mut uses = KdlNode::new("use");
                uses.insert("handler-from", rq.uses.handler_from.clone());
                if let Some(metrics) = &rq.uses.metrics {
                    uses.insert(
                        "metrics",
                        metrics.strip_prefix("prometheus:").unwrap_or(metrics),
                    );
                }
                child_nodes.push(uses);
            }
            Variant::Prometheus(cfg) => {
                if let Some(persist_path) = &cfg.persist_path {
                    let mut persist = KdlNode::new("persist");
                    persist.insert("path", persist_path.display().to_string());
                    persist.insert("interval", cfg.persist_interval.clone());
                    child_nodes.push(persist);
                }
            }
        }

        node
    }
}

impl KdlNodeWriteExt for Firewall {
    fn to_kdl_node(&self, _dummy: &str) -> KdlNode {
        let mut node = KdlNode::new("firewall");
        let children = node.ensure_children();
        let child_nodes = children.nodes_mut();

        let make_child = |name, value: KdlEntry| {
            let mut prop = KdlNode::new(name);
            prop.push(value);
            prop
        };
        let make_bool = |name, state: bool| {
            let mut prop = KdlNode::new(name);
            if !state {
                prop.push(state);
            }
            prop
        };

        if let Some(value) = self.enable {
            child_nodes.push(make_bool("enable", value));
        }
        if let Some(table_name) = &self.table {
            child_nodes.push(make_child("table", table_name.clone().into()));
        }
        if let Some(timeout) = &self.timeout {
            child_nodes.push(make_child("timeout", timeout.clone().into()));
        }
        if let Some(gc_interval) = &self.gc_interval {
            child_nodes.push(make_child("gc-interval", gc_interval.clone().into()));
        }
        if let Some(size) = self.size {
            child_nodes.push(make_child("size", i128::from(size).into()));
        }
        if let Some(priority) = self.priority {
            child_nodes.push(make_child("priorty", i128::from(priority).into()));
        }
        if let Some(value) = self.counters {
            child_nodes.push(make_bool("counters", value));
        }
        if !self.allow.is_empty() {
            let mut allows = KdlNode::new("allow");
            for entry in &self.allow {
                allows.push(entry.to_string());
            }
            child_nodes.push(allows);
        }

        let mut batch_entry = KdlNode::new("batch");
        if let Some(batch_size) = self.batch_size {
            batch_entry.push(("size", batch_size as i128));
        }
        if let Some(batch_flush_interval) = self.batch_flush_interval {
            batch_entry.push(("flush-interval", i128::from(batch_flush_interval)));
        }
        if self.batch_size.is_some() || self.batch_flush_interval.is_some() {
            child_nodes.push(batch_entry);
        }

        node
    }
}

impl KdlNodeWriteExt for Handler {
    fn to_kdl_node(&self, handler_name: &str) -> KdlNode {
        let mut node = KdlNode::new("declare-handler");
        node.push(KdlEntry::new(handler_name.to_owned()));
        if let Some(path) = &self.path {
            node.insert("path", path.display().to_string());
        }
        node.insert("language", self.language.to_string());
        if let Some(compiler) = &self.compiler {
            node.insert("compiler", compiler.display().to_string());
        }
        if let Some(config) = &self.config
            && !config.is_empty()
        {
            let children = node.ensure_children();
            let child_nodes = children.nodes_mut();

            for (name, value) in config {
                let node = figment_value_to_kdl_node(name, value);
                child_nodes.push(node);
            }
        }

        node
    }
}

#[allow(clippy::cast_possible_wrap)]
fn figment_value_to_kdl_node(name: &str, v: &Value) -> KdlNode {
    let mut node = KdlNode::new(name.to_owned());

    match v {
        Value::String(_, s) => {
            node.push(KdlEntry::new(s.to_owned()));
        }
        Value::Char(_, c) => {
            node.push(KdlEntry::new(c.to_string()));
        }
        Value::Bool(_, b) => {
            node.push(KdlEntry::new(*b));
        }
        Value::Num(_, n) => {
            if let Some(i) = n.to_i128() {
                node.push(KdlEntry::new(i));
            } else if let Some(i) = n.to_u128() {
                node.push(KdlEntry::new(i as i128));
            }
        }
        Value::Empty(_, _) => {}
        Value::Dict(_, d) => {
            if !d.is_empty() {
                let children = node.ensure_children();
                let child_nodes = children.nodes_mut();

                for (name, value) in d {
                    let node = figment_value_to_kdl_node(name, value);
                    child_nodes.push(node);
                }
            }
        }
        Value::Array(_, a) => {
            for value in a {
                let array_node = figment_value_to_kdl_node("", value);
                for entry in array_node.entries() {
                    node.push(entry.clone());
                }
            }
        }
    }

    node
}