liminal-server 0.27.3

Standalone server for the liminal messaging bus
Documentation
//! ACCESS-012 R2: the lifecycle on an open exchange. There is no session
//! and no decision: the exchange gates nothing, so a verb acts at once under
//! the holder the connection declared (`open:<name>` or `open:anonymous`),
//! and a list answers every service, since an open exchange keeps no secret
//! from the machine it serves. Creating places nothing in Lys: the registry
//! runs under the network `open` with no placer.

use std::sync::Arc;

use crate::services::lifecycle::{Lifecycle, LifecycleError, ServiceRecord};

/// Serves `verb` for `holder` with `body`, answering the record acted on.
pub(super) fn serve(
    lifecycle: &Arc<Lifecycle>,
    holder: &str,
    verb: &str,
    operation: &str,
    body: &serde_json::Value,
    now_ms: u64,
) -> Result<serde_json::Value, String> {
    if verb == "list" {
        return lifecycle.list(|_| true).map_err(|error| error.to_string());
    }
    let field = |name: &str| {
        body.get(name)
            .and_then(serde_json::Value::as_str)
            .map(str::to_owned)
            .ok_or_else(|| format!("payload names no {name}"))
    };
    let record: Result<ServiceRecord, LifecycleError> = match verb {
        "create" => lifecycle.create(
            &field("template")?,
            &field("name")?,
            holder,
            operation,
            now_ms,
        ),
        "deploy" => lifecycle.deploy(&field("id")?, holder),
        "wake" => lifecycle.wake(&field("id")?, holder),
        "hold" => lifecycle.hold(&field("id")?, holder, now_ms),
        _ => lifecycle.retire(&field("id")?, holder, now_ms),
    };
    let record = record.map_err(|error| error.to_string())?;
    Ok(serde_json::json!({"outcome": "acted", "holder": holder, "service": record}))
}