sim-lib-server 0.1.0-rc.1

SIM workspace package for sim lib server.
Documentation
use std::{net::TcpListener, sync::Arc};

use sim_kernel::{Consistency, EvalRequest, Expr, ReadPolicy, Symbol};

use crate::{
    EvalSite, FrameKind, ServerAddress, ServerFrame, eval_request_from_frame,
    server_frame_from_request,
};

use super::super::{connect_transport_site_with_loopback, register_loopback_transport_endpoint};
use super::support::{codecs, cx};

#[derive(Clone)]
struct LanPeerSite {
    address: ServerAddress,
    codecs: Vec<Symbol>,
}

impl EvalSite for LanPeerSite {
    fn site_kind(&self) -> &'static str {
        "lan-peer"
    }

    fn address(&self) -> &ServerAddress {
        &self.address
    }

    fn codecs(&self) -> &[Symbol] {
        &self.codecs
    }

    fn answer(
        &self,
        cx: &mut sim_kernel::Cx,
        frame: ServerFrame,
    ) -> sim_kernel::Result<ServerFrame> {
        let expr = eval_request_from_frame(cx, &frame)?.expr;
        let mut reply = ServerFrame::from_expr(
            cx,
            frame.codec.clone(),
            FrameKind::Response,
            &expr,
            frame.envelope.consistency,
            Vec::new(),
            false,
        )?;
        reply.correlate = frame.msg_id;
        Ok(reply)
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}

#[test]
fn lan_peer_loopback_routes_fake_distributed_node() {
    let address = unused_loopback_tcp_address();
    let registration = register_loopback_transport_endpoint(
        address.clone(),
        Arc::new(LanPeerSite {
            address: address.clone(),
            codecs: codecs(),
        }),
    )
    .unwrap();
    assert_eq!(registration.address(), &address);

    let mut cx = cx();
    cx.grant_named("network");
    let (client, codec) =
        connect_transport_site_with_loopback(&mut cx, address.clone(), codecs(), true).unwrap();
    let request = server_frame_from_request(
        &mut cx,
        &codec,
        EvalRequest {
            expr: lan_peer_payload(),
            mode: sim_kernel::EvalMode::Eval,
            result_shape: None,
            answer_limit: None,
            stream_buffer: None,
            stream: false,
            required_capabilities: Vec::new(),
            deadline: None,
            consistency: Consistency::RemoteOnly,
            trace: false,
        },
    )
    .unwrap();

    let reply = client.answer(&mut cx, request).unwrap();
    assert_eq!(reply.kind, FrameKind::Response);
    assert_eq!(
        reply.decode_expr(&mut cx, ReadPolicy::default()).unwrap(),
        lan_peer_payload()
    );
    registration.close().unwrap();
}

fn lan_peer_payload() -> Expr {
    Expr::Map(vec![
        (
            Expr::Symbol(Symbol::new("site")),
            Expr::Symbol(Symbol::qualified("stream/site", "lan-peer")),
        ),
        (
            Expr::Symbol(Symbol::new("mode")),
            Expr::Symbol(Symbol::qualified("stream/lan-mode", "jitter-buffered")),
        ),
    ])
}

fn unused_loopback_tcp_address() -> ServerAddress {
    let listener = TcpListener::bind(("127.0.0.1", 0)).unwrap();
    let port = listener.local_addr().unwrap().port();
    drop(listener);
    ServerAddress::Tcp {
        host: "127.0.0.1".to_owned(),
        port,
    }
}