liminal-server 0.28.6

Standalone server for the liminal messaging bus
Documentation
//! A construction act Lys answers outright is carried out at once. Lys answers outright only when
//! a person granted the act outright, so no person decided this act: its receipt names the grant as
//! its authority and Lys as the decider, never a person who did not see it. The grant's responsible
//! person is recorded as answerable for the site, which is what lets them call its trial. (Lys never
//! lets a grant's responsible person decide a draft, so a person working alone could otherwise
//! never build anything.) On an open exchange the declared holder's own act is applied through the
//! same path (ACCESS-015).

use super::super::Lifecycle;
use super::{SiteAct, SiteError};
use crate::auth_lys::live::drafts::ApprovalTransition;

impl Lifecycle {
    /// Applies `act` under the outright `grant`, keyed by the caller's `operation`.
    ///
    /// # Errors
    /// The act's own refusal (an existing site, a service not building), or a store failure.
    pub fn apply_outright(
        &self,
        act: &SiteAct,
        grant: &str,
        operation: &str,
        words: &str,
        at_ms: u64,
    ) -> Result<serde_json::Value, SiteError> {
        self.apply_now(
            act,
            &ApprovalTransition {
                draft: format!("grant:{grant}"),
                digest: lys_pass::drafts::request_digest(words),
                approved_by: vec!["lys".to_owned()],
                executed_at_ms: at_ms,
            },
            at_ms,
        )?;
        Ok(serde_json::json!({
            "state": "executed",
            "grant": grant,
            "approved_by": "lys",
            "responsible": act.responsible,
            "operation": operation,
        }))
    }

    /// Applies `act` as its declared holder's own (ACCESS-015 R2): on an open
    /// exchange the holder who asks is the one who approves, and the record
    /// says so.
    ///
    /// # Errors
    /// The `request_bytes` bound, the act's own refusal, or a store failure.
    pub fn apply_declared(
        &self,
        act: &SiteAct,
        operation: &str,
        at_ms: u64,
    ) -> Result<serde_json::Value, SiteError> {
        let words = serde_json::to_string(act).map_err(|_| SiteError::Store)?;
        if words.len() > self.site_bindings()?.limits.request_bytes.get() {
            return Err(SiteError::Bound("request_bytes"));
        }
        self.apply_now(
            act,
            &ApprovalTransition {
                draft: format!("{}:{operation}", act.holder),
                digest: lys_pass::drafts::request_digest(&words),
                approved_by: vec![act.holder.clone()],
                executed_at_ms: at_ms,
            },
            at_ms,
        )?;
        Ok(serde_json::json!({
            "state": "executed",
            "grant": crate::agents::open_session::OPEN_GRANT,
            "approved_by": act.holder,
            "responsible": act.responsible,
            "operation": operation,
        }))
    }

    /// The one apply both answers share: the act on a candidate snapshot,
    /// one commit, then the retained values refreshed.
    fn apply_now(
        &self,
        act: &SiteAct,
        transition: &ApprovalTransition,
        at_ms: u64,
    ) -> Result<(), SiteError> {
        let mut registry = self.lock()?;
        let mut snapshot = Self::snapshot(&registry);
        self.apply_site_act(&mut snapshot, act, transition, at_ms, &registry.trials)?;
        super::storage::commit(self, &mut registry, &snapshot)?;
        drop(registry);
        self.refresh_sites()
    }
}

#[cfg(test)]
#[path = "outright_tests.rs"]
mod tests;