liminal-server 0.25.4

Standalone server for the liminal messaging bus
Documentation
use std::io::{Read, Write};
use std::net::{SocketAddr, TcpStream};
use std::sync::{Arc, Mutex, PoisonError};
use std::thread;
use std::time::{Duration, Instant};

use serde_json::Value;

use super::{
    OperatorCredentialReissueRefusal, OperatorCredentialReissueRequest, OperatorCredentialReissuer,
    ServedState, response_for_request, start_health_server,
};
use crate::health::checks::{
    ClusterReadiness, ReadinessCondition, ReadinessState, SharedReadinessState,
};

fn loopback_ephemeral() -> Result<SocketAddr, Box<dyn std::error::Error>> {
    Ok("127.0.0.1:0".parse()?)
}

/// The request-level tests answer from readiness alone; the refused-load
/// surface stays uninstalled, which is the state a server is in before its
/// participant handler exists.
fn served(readiness: SharedReadinessState) -> ServedState {
    ServedState {
        started_at: 1,
        drafts: Arc::new(Mutex::new(None)),
        grant_stream: Arc::new(std::sync::OnceLock::new()),
        lys_root: Arc::new(std::sync::OnceLock::new()),
        readiness,
        unloadable: crate::health::unloadable::SharedUnloadableConversations::default(),
        reissue: crate::health::reissue::SharedOperatorCredentialReissue::default(),
        reclaim: crate::health::reclaim_route::SharedReclaimSpine::default(),
        ephemeral_sweep: Arc::new(std::sync::OnceLock::new()),
        listen_addresses: Arc::new(std::sync::OnceLock::new()),
        link_bridges: crate::link_bridge::BridgeRegistry::default(),
    }
}

fn get(address: SocketAddr, path: &str) -> Result<String, Box<dyn std::error::Error>> {
    let mut stream = TcpStream::connect(address)?;
    stream.set_read_timeout(Some(Duration::from_secs(2)))?;
    let request = format!("GET {path} HTTP/1.1\r\nHost: localhost\r\n\r\n");
    stream.write_all(request.as_bytes())?;

    let mut response = String::new();
    stream.read_to_string(&mut response)?;
    Ok(response)
}

fn assert_status(response: &str, status: u16) {
    let expected = format!("HTTP/1.1 {status} ");
    assert!(
        response.starts_with(&expected),
        "response status did not start with {expected}: {response}"
    );
}

fn body(response: &str) -> Result<&str, Box<dyn std::error::Error>> {
    let Some((_headers, body)) = response.split_once("\r\n\r\n") else {
        return Err("response did not contain a header/body separator".into());
    };
    Ok(body)
}

fn json_body(response: &str) -> Result<Value, Box<dyn std::error::Error>> {
    Ok(serde_json::from_str(body(response)?)?)
}

#[path = "health_tests.rs"]
mod health;
#[path = "lifecycle_tests.rs"]
mod lifecycle;
#[path = "reissue_tests.rs"]
mod reissue;

#[path = "grant_stream_tests.rs"]
mod grant_stream;
#[path = "lys_root_tests.rs"]
mod lys_root;