liminal-server 0.25.4

Standalone server for the liminal messaging bus
Documentation
//! The one approved-draft store, dispatching to the registry that owns the target.

use super::{
    AgentDraftStore, ApprovalEvidence, ApprovalTransition, AtomicDraftStore, DraftError,
    issuer_approval,
};
use lys_pass::drafts::{ApprovedDraft, Execution};
use std::num::NonZeroUsize;

/// Dispatches through the owning atomic registry, sharing no unapproved command.
pub struct TargetDraftStore {
    pub agents: AgentDraftStore,
    pub sites: crate::services::lifecycle::site::executor::SiteDraftStore,
}
impl TargetDraftStore {
    fn target(&mut self, draft: &ApprovedDraft) -> Result<&mut dyn AtomicDraftStore, DraftError> {
        match draft.target.kind.as_str() {
            "liminal.agent" => Ok(&mut self.agents),
            "liminal.network" if draft.target.action == "create_site" => Ok(&mut self.sites),
            "liminal.service" | "liminal.template" => Ok(&mut self.sites),
            _ => Err(DraftError::Contract),
        }
    }
}
impl AtomicDraftStore for TargetDraftStore {
    fn receipt(&self, id: &str) -> Result<Option<Execution>, DraftError> {
        let agent = self.agents.receipt(id)?;
        let site = self.sites.receipt(id)?;
        if agent.is_some() && site.is_some() {
            return Err(DraftError::ReceiptMismatch);
        }
        Ok(agent.or(site))
    }
    fn approval(&self, draft: &ApprovedDraft) -> Result<ApprovalEvidence, DraftError> {
        issuer_approval(&self.agents.journal, draft)
    }
    fn commit(
        &mut self,
        draft: &ApprovedDraft,
        approval: &ApprovalTransition,
    ) -> Result<Execution, DraftError> {
        let bound = self.agents.journal.read(|snapshot| {
            snapshot
                .prepared
                .values()
                .any(|prepared| prepared.draft.as_deref() == Some(&draft.id))
        })?;
        if !bound {
            return self.agents.commit(draft, approval);
        }
        self.target(draft)?.commit(draft, approval)
    }
    fn acknowledged(&self, id: &str) -> Result<bool, DraftError> {
        if self.receipt_owner(id)? {
            self.agents.acknowledged(id)
        } else {
            self.sites.acknowledged(id)
        }
    }
    fn acknowledge(&mut self, id: &str, receipt: &Execution) -> Result<(), DraftError> {
        if self.receipt_owner(id)? {
            self.agents.acknowledge(id, receipt)
        } else {
            self.sites.acknowledge(id, receipt)
        }
    }
    fn pending_acknowledgments(
        &self,
        limit: NonZeroUsize,
    ) -> Result<Vec<ApprovedDraft>, DraftError> {
        let mut pending = self.agents.pending_acknowledgments(limit)?;
        pending.extend(self.sites.pending_acknowledgments(limit)?);
        if pending.len() > limit.get() {
            return Err(DraftError::Bound);
        }
        Ok(pending)
    }
    fn deliver_outcome(
        &mut self,
        draft: &ApprovedDraft,
        receipt: &Execution,
    ) -> Result<(), DraftError> {
        if self.receipt_owner(&draft.id)? {
            self.agents.deliver_outcome(draft, receipt)
        } else {
            self.sites.deliver_outcome(draft, receipt)
        }
    }
}