NamedMux

class NamedMux(delegate: Seam, scope: CoroutineScope)

String-keyed multiplexer over a Seam — the unbounded-namespace sibling of MuxSeam.

Produces independent Seam views — one per channel name — that share a single upstream collection of delegate's Seam.incoming. This satisfies the kuilt contract that Seam.incoming is single-collection: only NamedMux ever collects from delegate; each channel view subscribes to the internally-shared flow.

Where MuxSeam tags frames with a single byte (a hard ceiling of 256 channels, suited to a fixed handful of internal channels), NamedMux tags frames with a UTF-8 name, giving an effectively unbounded application namespace. The two compose by nesting: a MuxSeam tag can carry a whole NamedMux subtree, so only that subtree pays the wider header.

Framing

Every outbound frame is prefixed with [len:1 byte][name UTF-8], where len is the number of UTF-8 bytes in the name (1..255). Every inbound frame is filtered by its decoded name and delivered to the matching channel view with the header stripped. Frames whose name matches no channel view are silently discarded.

Late-subscriber semantics

The shared upstream is started with replay = 0. Frames emitted before a channel view begins collecting are not replayed — this is best-effort delivery, suitable for Quilter-grade consumers (which heal gaps via FullState + resend) but not for raw at-least-once consumers, which must layer their own reliability. Identical caveat to MuxSeam.

Channel identity

channel is idempotent: calling it twice with the same name returns the same Seam instance. Thread-safe: concurrent channel calls are serialised by an internal reentrant lock so the backing map is never raced.

Parameters

delegate

the underlying Seam whose Seam.incoming this class owns.

scope

a CoroutineScope for the shared upstream collector.

Samples

runTest(UnconfinedTestDispatcher()) {
    val loom = InMemoryLoom()
    val rawA = loom.host(Pattern("named-mux-demo"))
    val rawB = loom.join(InMemoryTag("b"))

    val muxA = NamedMux(rawA, backgroundScope)
    val muxB = NamedMux(rawB, backgroundScope)

    val chatA: Seam = muxA.channel("chat")
    val chatB: Seam = muxB.channel("chat")
    val cursorA: Seam = muxA.channel("cursors")

    // channel() is idempotent — same name returns the same Seam instance.
    check(muxA.channel("chat") === chatA)
    check(chatA !== cursorA)

    // Frames sent on "chat" arrive only on the matching channel view.
    val received = async { chatB.incoming.first() }
    chatA.broadcast("hello".encodeToByteArray())
    check(received.await().decodeToString() == "hello")
}

Constructors

Link copied to clipboard
constructor(delegate: Seam, scope: CoroutineScope)

Functions

Link copied to clipboard
fun channel(name: String): Seam

Returns a Seam view carrying only frames named name.