liminal-server 0.27.3

Standalone server for the liminal messaging bus
Documentation
//! ACCESS-011 R3: `/health` says how the exchange admits and decides.

use crate::config::ServerConfig;
use crate::config::types::AccessMode;

/// `access: {mode, reach?, decisions?}` beside `lys_root`: the mode every
/// exchange has, the reach of an open one, the decisions word of a Lys one.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
pub struct AccessHealth {
    /// `open` or `gated`.
    pub mode: &'static str,
    /// `loopback` or `network`; only in open mode.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reach: Option<&'static str>,
    /// `enforce` or `advise`; only with `[auth.lys]`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub decisions: Option<&'static str>,
}

impl From<&ServerConfig> for AccessHealth {
    fn from(config: &ServerConfig) -> Self {
        let mode = config.access_mode();
        Self {
            mode: match mode {
                AccessMode::Open => "open",
                AccessMode::Gated => "gated",
            },
            reach: (mode == AccessMode::Open).then(|| config.open_reach().word()),
            decisions: config
                .auth
                .as_ref()
                .and_then(|auth| auth.lys.as_ref())
                .map(|lys| lys.decisions.word()),
        }
    }
}

impl AccessHealth {
    /// A gated exchange on its bearer alone: what a health test that is not
    /// about access models.
    pub const BEARER: Self = Self {
        mode: "gated",
        reach: None,
        decisions: None,
    };

    /// The same answer as one line, for `liminal check`:
    /// `mode open, reach network` or `mode gated, decisions advise`.
    #[must_use]
    pub fn words(&self) -> String {
        let mut words = vec![format!("mode {}", self.mode)];
        words.extend(self.reach.map(|reach| format!("reach {reach}")));
        words.extend(
            self.decisions
                .map(|decisions| format!("decisions {decisions}")),
        );
        words.join(", ")
    }
}