use std::sync::Arc;
use super::effects::SiteEffects;
use super::{BuilderGrants, SiteAct, SiteChange, SiteError};
use crate::agents::open_session::{OPEN_GRANT, OPEN_KIND};
use crate::auth_lys::session::LysSession;
use crate::server::connection::declared_holder::{ANONYMOUS, PREFIX};
use crate::services::lifecycle::Lifecycle;
pub const NEEDS_A_NAME: &str = "construction_needs_a_name: an anonymous seat acts for no one; \
liminal seat init --open <server> --name <name>";
#[must_use]
pub fn builds(session: &dyn LysSession) -> bool {
match session.holder_kind() {
Some("agent") => true,
Some(OPEN_KIND) => session.holder() != ANONYMOUS,
_ => false,
}
}
#[must_use]
pub fn answerable(session: &dyn LysSession) -> Option<String> {
match session.holder_kind() {
Some("person") => Some(session.holder().to_owned()),
Some(OPEN_KIND) if session.holder() != ANONYMOUS => {
Some(format!("{PREFIX}{}", session.holder()))
}
_ => None,
}
}
#[derive(Debug)]
pub struct DeclaredActs;
impl crate::server::connection::services::SiteDraftHolder for DeclaredActs {
fn hold(
&self,
lifecycle: &Lifecycle,
session: &dyn LysSession,
operation: &str,
target: &str,
change: SiteChange,
at_ms: u64,
) -> Result<serde_json::Value, SiteError> {
if session.holder_kind() != Some(OPEN_KIND) {
return Err(SiteError::Invalid("construction holder kind"));
}
let holder = answerable(session).ok_or_else(|| SiteError::Refused(NEEDS_A_NAME.into()))?;
let act = SiteAct {
target: target.into(),
holder: holder.clone(),
responsible: holder,
change,
};
lifecycle.apply_declared(&act, operation, at_ms)
}
}
pub struct OpenSiteEffects {
agents: Arc<crate::agents::runtime::Agents>,
}
impl OpenSiteEffects {
#[must_use]
pub const fn new(agents: Arc<crate::agents::runtime::Agents>) -> Self {
Self { agents }
}
}
impl SiteEffects for OpenSiteEffects {
fn agent_owner(&self, agent: &str) -> Result<String, SiteError> {
let record = self.agents.registry().record(agent).map_err(|_| {
SiteError::Refused(format!(
"builder {agent} has no station on this exchange; its seat listens to its \
inbox once to place it"
))
})?;
if !record.active() {
return Err(SiteError::Refused(format!("agent {agent} is retired")));
}
Ok(record.owner)
}
fn bind(
&self,
_draft: &str,
_site: &str,
agent: &str,
_at_ms: u64,
) -> Result<BuilderGrants, SiteError> {
self.agent_owner(agent)?;
Ok(BuilderGrants {
plan: OPEN_GRANT.into(),
serve: OPEN_GRANT.into(),
})
}
fn revoke(&self, _draft: &str, _label: &str, _grant: &str) -> Result<(), SiteError> {
Ok(())
}
fn open(&self) -> bool {
true
}
}
#[cfg(test)]
#[path = "declared_tests.rs"]
mod tests;