liminal-cli 0.3.4

The liminal command: serve the network, maintain its stores, or serve its discovery MCP over stdio
Documentation
use super::super::RailError;
use super::{Live, Source};

/// Only a Connect refusal can renew: no admitted application act is repeated.
fn expired_admission(error: &RailError) -> bool {
    let RailError::Refused(message) = error else {
        return false;
    };
    message.starts_with("connection error: server rejected")
        && message.ends_with(": lys pass admission refused: pass_expired")
}

impl Live {
    pub(super) fn admit<T>(
        &self,
        connect: impl FnMut(&[u8]) -> Result<T, RailError>,
    ) -> Result<T, RailError> {
        Self::admit_with(
            connect,
            || {
                let Source::Lys(agent) = &self.source else {
                    return Ok(false);
                };
                agent
                    .forget_expired_pass()
                    .map_err(|error| RailError::Refused(error.0))
            },
            || self.credential(),
        )
    }

    fn admit_with<T>(
        mut connect: impl FnMut(&[u8]) -> Result<T, RailError>,
        renew: impl FnOnce() -> Result<bool, RailError>,
        credential: impl Fn() -> Result<Vec<u8>, RailError>,
    ) -> Result<T, RailError> {
        let answer = connect(&credential()?);
        if let Err(error) = &answer
            && expired_admission(error)
            && renew()?
        {
            return connect(&credential()?);
        }
        answer
    }
}

#[cfg(test)]
mod tests {
    use super::{Live, RailError};
    use std::cell::Cell;

    #[test]
    fn an_expired_admission_asks_once_more_and_keeps_a_second_refusal() {
        let calls = Cell::new(0);
        let renewals = Cell::new(0);
        let error = RailError::Refused("connection error: server rejected connection (reason 6): lys pass admission refused: pass_expired".to_owned());
        let result: Result<(), _> = Live::admit_with(
            |_| {
                calls.set(calls.get() + 1);
                Err(error.clone())
            },
            || {
                renewals.set(renewals.get() + 1);
                Ok(true)
            },
            || Ok(Vec::new()),
        );
        assert_eq!(result, Err(error));
        assert_eq!(calls.get(), 2);
        assert_eq!(renewals.get(), 1);
    }

    #[test]
    fn an_application_refusal_and_an_unproven_pass_are_never_repeated() {
        for text in [
            "conversation 1: pass_expired",
            "connection error: server rejected connection (reason 6): lys pass admission refused: signature_refused",
        ] {
            let calls = Cell::new(0);
            let renewals = Cell::new(0);
            let result: Result<(), _> = Live::admit_with(
                |_| {
                    calls.set(calls.get() + 1);
                    Err(RailError::Refused(text.to_owned()))
                },
                || {
                    renewals.set(renewals.get() + 1);
                    Err(RailError::Refused("this refusal cannot renew".to_owned()))
                },
                || Ok(Vec::new()),
            );
            assert_eq!(result, Err(RailError::Refused(text.to_owned())));
            assert_eq!(calls.get(), 1);
            assert_eq!(renewals.get(), 0);
        }
    }
}