sim-lib-web-bridge 0.1.0

Session and transport bridge over realize/EvalFabric: the Intent/Scene bus for the SIM Web-UI (WEBUI_4).
Documentation
use sim_kernel::{Expr, Symbol};
use sim_lib_stream_core::{
    ClockDomain, LatencyClass, PcmPacket, PlacedFragment, RateContract, StreamDirection,
    StreamEnvelope, StreamMedia, StreamPacket, TransportProfile, stream_edge,
};

use crate::{
    BrowserBridgeLane, BrowserPlacementRequest, BrowserWasmEngine,
    browser_audio_worklet_entry_symbol, browser_server_only_refusal_diagnostic,
    browser_wasm_engine_entry_symbol, browser_wasm_site_symbol,
};

#[test]
fn headless_browser_wasm_runs_placed_graph_and_carries_bridge_lanes() {
    let report = BrowserPlacementRequest::new(fragment(), browser_engine())
        .run_headless()
        .unwrap();

    assert_eq!(report.site(), &browser_wasm_site_symbol());
    assert_eq!(report.engine().transport_kind(), crate::TransportKind::Wasm);
    assert!(report.engine().audio_worklet_capable());
    assert!(!report.engine().uses_server_audio_tunnel());
    assert_eq!(
        report.engine().entry_points().engine(),
        &browser_wasm_engine_entry_symbol()
    );
    assert_eq!(
        report.engine().entry_points().audio_worklet(),
        &browser_audio_worklet_entry_symbol()
    );
    assert_eq!(
        report.lanes(),
        &[
            BrowserBridgeLane::Ui,
            BrowserBridgeLane::Preview,
            BrowserBridgeLane::Trace,
        ]
    );
    assert_eq!(report.output_envelopes().len(), 3);
}

#[test]
fn server_only_node_is_refused_for_browser_wasm() {
    let err = BrowserPlacementRequest::new(fragment(), browser_engine())
        .with_server_only(true)
        .run_headless()
        .unwrap_err();

    assert!(
        format!("{err}").contains(&browser_server_only_refusal_diagnostic().as_qualified_str())
    );
}

fn browser_engine() -> BrowserWasmEngine {
    BrowserWasmEngine::browser_local(Symbol::qualified("stream/engine", "browser-headless"))
}

fn fragment() -> PlacedFragment {
    let ui = data_edge(
        "ui",
        RateContract::new(ClockDomain::BrowserFrame, LatencyClass::Interactive, None),
        Expr::String("scene-update".to_owned()),
    );
    let preview = preview_edge();
    let trace = data_edge(
        "trace",
        RateContract::trace_step(),
        Expr::String("trace-step".to_owned()),
    );

    PlacedFragment::new(Symbol::new("browser-node"), Expr::Bool(true))
        .with_output_edge(ui)
        .with_output_edge(preview)
        .with_output_edge(trace)
}

fn data_edge(port: &str, rate: RateContract, payload: Expr) -> sim_lib_stream_core::StreamEdge {
    let edge = stream_edge(port, StreamMedia::Data, StreamDirection::Source, rate);
    let envelope = edge.result_envelope(0, payload).unwrap();
    edge.with_envelopes(vec![envelope])
}

fn preview_edge() -> sim_lib_stream_core::StreamEdge {
    let edge = stream_edge(
        "preview",
        StreamMedia::Pcm,
        StreamDirection::Source,
        RateContract::new(
            ClockDomain::BrowserFrame,
            LatencyClass::BufferedPreview,
            None,
        ),
    );
    let envelope = StreamEnvelope::new(
        edge.metadata().id().clone(),
        Symbol::qualified("stream/browser-packet", "preview-0"),
        StreamMedia::Pcm,
        StreamDirection::Source,
        0,
        Vec::new(),
        ClockDomain::BrowserFrame,
        TransportProfile::buffered_pcm_preview(),
        Vec::new(),
        StreamPacket::Pcm(PcmPacket::f32(1, 1, vec![0.25]).unwrap()),
    )
    .unwrap();
    edge.with_envelopes(vec![envelope])
}