Skip to content

kithara events

Pavel Litvinenko edited this page Sep 10, 2026 · 8 revisions

kithara-events

API and usage · All crates. The typed-channel contract is introduced by PR #354.

Scope and channel ownership

Each bus scope owns one channel per concrete event type. A subscription creates its channel lazily. Publishing visits the current scope and its ancestors, sending only through channels already created for that type. A parent publication never travels down to a child, and siblings cannot observe each other.

Scopes own channels independently of receivers. Dropping the last receiver leaves the channel available for a later subscription. A receiver reports Closed after the last bus retaining its scope is gone and its queued events have been drained. Descendants retain their ancestor scopes. Bus identifiers are monotonically allocated and never reused.

Channel capacity is fixed at root construction, clamped to at least one, and inherited by descendants. Each type receives that capacity independently. A lagging receiver gets Lagged with the number of lost events; queues never grow beyond their configured capacity. A publication without an existing channel does not create one. Routing uses no new allocation, although payload cloning retains the payload type's own semantics.

Events and consumer sets

This crate owns the typed bus, scope identity, envelopes and consumer-set machinery. It is featureless: domain selection belongs to consumers rather than the bus manifest. Domain event vocabularies are owned by their domain crates. Playback, route, and port event values live in kithara-play; committed session-transport facts live in kithara-host; queue lifecycle and item-stall events live in kithara-queue; HLS and DRM events live in kithara-hls; seek epochs live in kithara-stream.

Event is a marker for concrete Clone, Debug, Send, Sync, static values. EventSet adapts the exact member types a consumer observes into one receiver. Every Event is also a one-member EventSet. Multi-member sets use the EventSet derive, which supplies conversions, subscriptions and publication dispatch; they must not also derive derive_more::From.

Each member preserves channel order. Across members, declaration order is receive priority, not a global FIFO guarantee. Async receive skips channels that have reported Closed and terminates when all members close. Nonblocking receive returns lag immediately, scans past empty and closed members, reports Empty while any member is open, and otherwise reports Closed.

Envelope carries the value and publication metadata. Its map operation changes only the payload. EventMeta records publishing scope, hierarchy-wide sequence, timestamp, and inherited deck/track labels. A child label overrides a parent only where the child provides Some. Neither Envelope nor EventMeta has an external public constructor. The self-crate alias permits event derives inside the bus crate without a second implementation path.

Deferred publication

DeferredBus carries a narrow consumer set through a fixed ArrayQueue. Enqueue takes the hierarchy sequence and pushes without locks, allocations or clock reads. A full ring drops the event and increments its drop counter. Flush runs in the unchecked scheduler shell, stamps the current publication time, drains in producer order and dispatches each set member to its typed channel. It then publishes BusEvent::Overflow with the exact number dropped since the prior flush.

Broadcast send takes an internal lock and therefore stays outside the forbid-blocking decode core. Sequence reflects enqueue order; timestamp reflects flush time. Audio's deferred ring carries AudioLaneEvent, the Audio/Decoder pair owned by its producer surface.

Channel memory

A native probe measured Envelope sizes in bytes: Abr 96, Asset 128, Audio 128, Bus 72, Decoder 144, Dj 96, Downloader 208, Drm 112, Engine 88, File 88, Hls 128, Item 64, Player 104, Queue 96, Session 88, Transport 96.

At capacity 1024, adding an estimated 32 bytes per slot gives:

Consumer Channel estimate (bytes)
Native queue (six types) 811,008
Native item (seven types) 1,155,072
Web root (both sets) 1,966,080

These are channel storage estimates derived from measured envelope sizes, not process RSS measurements. Slot overhead remains approximate; heap allocations owned by payloads are excluded. All three totals remain within 25% of the design estimates.

Follow-ups

  • C14 may add an exhaustiveness check that every workspace type deriving Event appears in an EventSet or a typed subscription.
  • PlayerConfig may gain per-set channel capacities when one fixed capacity for every topic no longer fits measured memory and lag requirements. Today all topics use DEFAULT_EVENT_BUS_CAPACITY.

Clone this wiki locally