use figment::value::Value;
use kdl::{KdlDocument, KdlEntry, KdlNode};
use crate::config::{Config, Handler, Server, ServerVariant};
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"));
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));
}
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 {
ServerVariant::Http(_) => ("http-server", "http:"),
ServerVariant::HaproxySPOA(_) => ("haproxy-spoa-server", "haproxy-spoa:"),
ServerVariant::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 {
ServerVariant::Http(rq) | ServerVariant::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);
}
ServerVariant::Prometheus(cfg) => {
if let Some(persist_path) = &cfg.persist_path {
child_nodes.push(
persist_path
.display()
.to_string()
.to_kdl_node("persist-path"),
);
child_nodes.push(cfg.persist_interval.to_kdl_node("persist-interval"));
}
}
}
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 {
if !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
}