Salta ai contenuti

Read state: snapshots, outcomes, events and topics

Questa pagina è in inglese: in italiano ci sono per ora i tutorial e il glossario; menu, ricerca e navigazione sono in italiano.

Commands change state; everything else reads it. Pick the reader that fits who is reading.

Reader Use Where
a person or a model wants a summary text snapshot commands::takeSnapshot
your code wants to know what a command did the outcome of submit commands::Outcome
your C++ UI or logic wants the current values the domain’s model and its events e.g. setlist::Show::model(), subscribe
a web page wants live state a topic (snapshot, then deltas) ui_bridge::TopicSource
a meter or a playhead, many times a second a stream ui_bridge::StreamSource

Reading never changes anything, and nothing you read is a back door: to change a value, submit a command (Add a command).

Every CommandTarget fills a snapshot at three levels (brief, standard, full); takeSnapshot renders it within a character budget and says what it left out:

const auto text = commands::takeSnapshot (show, commands::SnapshotLevel::brief, 300);

The brief level also carries named values (StateValue, for example tempo_bpm) that protocol surfaces such as OSCQuery publish. A model reads the brief snapshot before it acts; a person reads it in a status line. examples/setlist/show prints the set list’s brief snapshot with show.brief().

CommandSession::submit returns what happened:

const auto outcome = session.submit (commands::makeCommand ("setlist.step_song", R"({"direction":"forward"})"),
commands::personProfile(), context);
switch (outcome.status)
{
case commands::Outcome::Status::applied: /* outcome.description, outcome.changes */ break;
case commands::Outcome::Status::needsConfirmation: /* ask a person; then session.confirm (outcome.confirmationId, ...) */ break;
case commands::Outcome::Status::rejected: /* commands::describeProblems (outcome.problems) */ break;
}

Each Change has the object, the property, and the value before and after, as JSON. outcome.revision is the show’s revision after the request: a counter that grows by one per applied request, so a reader can tell whether it has seen the latest state.

Domains expose their state as plain structs and tell listeners about events that do not come from commands (a song finished loading, a device left). For the set list:

struct Printer final : setlist::ShowEventListener
{
void showEvent (const setlist::ShowEvent& e) override { /* e.kind, e.songName, e.text */ }
};
Printer printer;
auto subscription = show.subscribe (printer); // unsubscribes when it is destroyed
const auto& model = show.model(); // model.list.songs, model.performance.current, ...

Events arrive on the control thread. Keep the subscription object alive as long as the listener.

A page subscribes to a topic and receives a snapshot, then JSON Merge Patch deltas, throttled to the topic’s maximum rate. To expose a domain’s state, implement ui_bridge::TopicSource (a descriptor with a JSON Schema and a read()); tutorial 3 and Build a web UI show it. The bridge adds the session topic (show mode, pending confirmations) and ui.theme.

Values that change every block are not state: they are streams. The audio side publishes them (atomics or a lock-free FIFO); a StreamSource copies the latest values into a frame on the control thread, and the page calls client.streamSubscribe ("mixer.meters", 30, onFrame). A slow reader skips frames; it never queues them.

Reference: specs/commands.md §3.4 (snapshots), specs/ui_bridge.md (topics and streams).