liminal-server 0.24.1

Standalone server for the liminal messaging bus
Documentation
//! Real TCP acceptance. No mock server, timeout, polling or clock wait.

use std::io::{Read, Write};
use std::net::{SocketAddr, TcpStream};
use std::sync::Arc;

use liminal::protocol::{Frame, ProtocolError, ProtocolVersion, decode, encode, encoded_len};
use serde_json::json;

use super::records::{AgentEvent, AgentHarness, AgentSpec};
use super::test_support::{Fixture, FixtureIssuer, TestResult, approved, signed_pass};
use crate::server::connection::{
    ConnectionServices, ConnectionSupervisor, LiminalConnectionServices,
};
use crate::server::listener::ServerListener;

struct Exchange {
    listener: Option<ServerListener>,
    supervisor: ConnectionSupervisor,
    services: Arc<LiminalConnectionServices>,
    fixture: Fixture,
    keys: tempfile::TempDir,
}

impl Exchange {
    fn new() -> Result<Self, Box<dyn std::error::Error>> {
        let fixture = Fixture::new()?;
        let keys = tempfile::tempdir()?;
        let keys_path = keys.path().join("issuer.json");
        let (issuer_keys, pass) = signed_pass("a")?;
        drop(pass);
        std::fs::write(&keys_path, issuer_keys)?;
        let config: crate::config::types::ServerConfig = serde_json::from_value(json!({
            "listen_address":"127.0.0.1:0","health_listen_address":"127.0.0.1:0",
            "channels":[],"routing_rules":[],"drain_timeout_ms":0,
            "limits":{"max_channels":64},
            "auth":{"token":"fixture-bearer","lys":{"issuer":"https://agent.fixture",
                "network_id":"fixture-network","keys_path":keys_path,"agents":{}}}}))?;
        let store: Arc<dyn liminal::durability::DurableStore> = fixture.counts.clone();
        let services = Arc::new(
            LiminalConnectionServices::from_config_with_store(&config, store)?
                .with_agent_fixture("fixture-network", Arc::new(FixtureIssuer::default()))?,
        );
        let agents = services.agents().ok_or("agent runtime missing")?;
        for name in ["a", "b"] {
            agents.execute_approved(&approved(
                &format!("create-{name}"),
                name,
                "fixture-owner",
                AgentEvent::Create(AgentSpec {
                    harness: AgentHarness::Cdx,
                    purpose: "Build one service.".into(),
                    service: None,
                }),
            )?)?;
            services.agent_created(name)?;
        }
        let supervisor = ConnectionSupervisor::builder(services.clone())
            .auth(config.auth.as_ref().ok_or("fixture auth missing")?)?
            .limits(config.limits)
            .build()?;
        let listener = ServerListener::bind(&config, supervisor.clone())?;
        Ok(Self {
            listener: Some(listener),
            supervisor,
            services,
            fixture,
            keys,
        })
    }

    fn address(&self) -> Result<SocketAddr, Box<dyn std::error::Error>> {
        Ok(self
            .listener
            .as_ref()
            .ok_or("listener absent")?
            .local_addr())
    }

    fn finish(mut self) -> TestResult {
        self.listener.take().ok_or("listener absent")?.shutdown()?;
        self.supervisor.shutdown();
        self.services.release_store_holders()?;
        drop(self.services);
        drop(self.fixture);
        drop(self.keys);
        Ok(())
    }
}

struct Client {
    stream: TcpStream,
    buffer: Vec<u8>,
    next: u32,
}

impl Client {
    fn connect(address: SocketAddr, holder: &str) -> Result<Self, Box<dyn std::error::Error>> {
        let mut client = Self {
            stream: TcpStream::connect(address)?,
            buffer: Vec::new(),
            next: 1,
        };
        let (keys, pass) = signed_pass(holder)?;
        drop(keys);
        client.write(&Frame::Connect {
            flags: 0,
            min_version: ProtocolVersion::new(1, 0),
            max_version: ProtocolVersion::new(1, 0),
            auth_token: liminal_protocol::credential::WireCredential::lys_record(pass.as_bytes()),
        })?;
        assert!(matches!(client.read()?, Frame::ConnectAck { .. }));
        Ok(client)
    }
    fn write(&mut self, frame: &Frame) -> TestResult {
        let mut bytes = vec![0; encoded_len(frame)?];
        let n = encode(frame, &mut bytes)?;
        self.stream
            .write_all(bytes.get(..n).ok_or("encoded frame overrun")?)?;
        Ok(())
    }
    fn read(&mut self) -> Result<Frame, Box<dyn std::error::Error>> {
        loop {
            match decode(&self.buffer) {
                Ok((frame, n)) => {
                    self.buffer.drain(..n);
                    return Ok(frame);
                }
                Err(
                    ProtocolError::IncompleteHeader { .. } | ProtocolError::TruncatedPayload { .. },
                ) => {
                    let mut byte = [0; 4096];
                    let n = self.stream.read(&mut byte)?;
                    if n == 0 {
                        return Err("server closed before the expected signal".into());
                    }
                    self.buffer
                        .extend_from_slice(byte.get(..n).ok_or("read buffer overrun")?);
                    if self.buffer.len()
                        > crate::config::types::LimitsConfig::DEFAULT_MAX_CONNECTION_INBOX_BYTES
                    {
                        return Err("fixture frame exceeded the configured inbox bound".into());
                    }
                }
                Err(error) => return Err(error.into()),
            }
        }
    }
    fn subscribe(&mut self, subject: &str) -> Result<Frame, Box<dyn std::error::Error>> {
        let stream_id = self.next;
        self.next += 1;
        self.write(&Frame::Subscribe {
            flags: 0,
            stream_id,
            channel: subject.into(),
            accepted_schemas: Vec::new(),
            max_in_flight: 8,
        })?;
        self.read()
    }
    fn value(&mut self) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
        let Frame::Deliver { envelope, .. } = self.read()? else {
            return Err("expected metadata Deliver".into());
        };
        Ok(serde_json::from_slice(&envelope.payload)?)
    }
}

#[test]
fn agt002_real_wire_refuses_a_foreign_identity_and_a_duplicate_then_retains_presence_first()
-> TestResult {
    let exchange = Exchange::new()?;
    let address = exchange.address()?;
    let mut a = Client::connect(address, "a")?;
    let Frame::SubscribeError { message, .. } = a.subscribe("agents.b.inbox")? else {
        return Err("foreign identity admitted".into());
    };
    assert_eq!(message.as_deref(), Some("pass holder a is not agent b"));
    assert!(matches!(
        a.subscribe("agents.a.inbox")?,
        Frame::SubscribeAck { .. }
    ));
    let mut watch = Client::connect(address, "b")?;
    assert!(
        matches!(
            watch.subscribe("agents.a.presence")?,
            Frame::SubscribeAck { .. }
        ),
        "ack precedes current value"
    );
    let current = watch.value()?;
    assert_eq!(current["present"], true);
    let connection = current["connection"].as_u64().ok_or("connection missing")?;
    let since_ms = current["at_ms"].as_u64().ok_or("at_ms missing")?;
    let message = liminal::protocol::MessageEnvelope::new(
        liminal::protocol::SchemaId::new([0; liminal::protocol::SchemaId::WIRE_LEN]),
        liminal::protocol::CausalContext::independent(),
        br#"{"text":"synthetic message"}"#.to_vec(),
    );
    watch.write(&Frame::new_publish(9, "agents.a.inbox", message)?)?;
    assert!(matches!(watch.read()?, Frame::PublishAck { .. }));
    let Frame::Deliver { envelope, .. } = a.read()? else {
        return Err("granted message did not arrive".into());
    };
    let body: serde_json::Value = serde_json::from_slice(&envelope.payload)?;
    let matched = body["text"].as_str() == Some("synthetic message");
    assert!(matched, "inbox body differed");
    let metadata = liminal::protocol::MessageEnvelope::new(
        liminal::protocol::SchemaId::new([0; liminal::protocol::SchemaId::WIRE_LEN]),
        liminal::protocol::CausalContext::independent(),
        b"{}".to_vec(),
    );
    a.write(&Frame::new_publish(10, "agents.a.state", metadata)?)?;
    let Frame::PublishError { message, .. } = a.read()? else {
        return Err("server-owned state was writable".into());
    };
    assert_eq!(
        message.as_deref(),
        Some("agent_subject_server_owned: agents.a.state")
    );
    let mut second = Client::connect(address, "a")?;
    let Frame::SubscribeError { message, .. } = second.subscribe("agents.a.inbox")? else {
        return Err("duplicate seat admitted".into());
    };
    assert_eq!(
        message,
        Some(format!(
            "agent a is already present on connection {connection}, held since unix ms \
             {since_ms}; the seat frees when that connection closes or its peer stops \
             answering keepalive (80 s), so give this client a seat of its own"
        ))
    );
    a.write(&Frame::Disconnect { flags: 0 })?;
    let gone = watch.value()?;
    assert_eq!(gone["present"], false);
    assert_eq!(gone["reason"], "client_close");
    assert!(matches!(
        second.subscribe("agents.a.inbox")?,
        Frame::SubscribeAck { .. }
    ));
    let returned = watch.value()?;
    assert_eq!(returned["present"], true);
    second.write(&Frame::Disconnect { flags: 0 })?;
    assert_eq!(watch.value()?["present"], false);
    drop(a);
    drop(second);
    drop(watch);
    exchange.finish()
}

/// A holder whose process ends frees the seat at once: its socket closes with
/// no Disconnect frame, the transport's close releases the seat, and the next
/// connection takes it. No keepalive and no clock is involved.
#[test]
fn a_holder_that_exits_without_a_disconnect_frees_its_seat_at_once() -> TestResult {
    let exchange = Exchange::new()?;
    let address = exchange.address()?;
    let mut a = Client::connect(address, "a")?;
    assert!(matches!(
        a.subscribe("agents.a.inbox")?,
        Frame::SubscribeAck { .. }
    ));
    let mut watch = Client::connect(address, "b")?;
    assert!(matches!(
        watch.subscribe("agents.a.presence")?,
        Frame::SubscribeAck { .. }
    ));
    assert_eq!(watch.value()?["present"], true);
    // The process exits: its socket closes, and no Disconnect frame is sent.
    drop(a);
    let gone = watch.value()?;
    assert_eq!(gone["present"], false, "{gone}");
    let mut second = Client::connect(address, "a")?;
    assert!(
        matches!(
            second.subscribe("agents.a.inbox")?,
            Frame::SubscribeAck { .. }
        ),
        "the seat of a holder that exited was not freed"
    );
    assert_eq!(watch.value()?["present"], true);
    second.write(&Frame::Disconnect { flags: 0 })?;
    drop(second);
    drop(watch);
    exchange.finish()
}