Skip to content

Push events

veriCue supports push-based event subscriptions alongside the standard request/response model. The client subscribes to a Qt-level event; the server then sends asynchronous type: "event" messages whenever it fires.

Subscription types

Subscribe commandPushed eventWhen it fires
subscribe_signal(path, signal)signal_emittedEvery time the signal fires
subscribe_property(path, property)property_changedEvery time the property's NOTIFY signal fires
subscribe_destroyed(path)object_destroyedOnce, when the QObject is destroyed

Event message shape

json
{
  "v": 1,
  "type": "event",
  "subscription_id": "sub-7",
  "event": "signal_emitted",
  "path": "MainWindow/okButton",
  "data": {
    "signal": "clicked",
    "args": [false]
  },
  "timestamp": "2026-06-21T10:42:13.001Z"
}

The data field depends on the event:

json
// signal_emitted
"data": { "signal": "clicked", "args": [false] }

// property_changed
"data": { "property": "text", "value": "Logged in" }

// object_destroyed
"data": { "path": "MainWindow/dialogX" }

Subscription lifecycle

  • Subscriptions are bound to the TCP connection. When you disconnect, every subscription on that connection is dropped server-side.
  • A subscription survives the QObject it tracks being temporarily destroyed and recreated - but only if the new instance is reachable by the same path.
  • For object_destroyed, after the event fires the subscription is automatically removed (one-shot).

Python

python
sub_id = await client.subscribe_signal(
    "MainWindow/okButton", "clicked",
    callback=lambda evt: print("Click:", evt["timestamp"]),
)

# Either consume from the shared queue …
event = await client.next_event(timeout=5.0)

# … or async-iterate every event
async for event in client.events():
    print(event)

# Cancel
await client.unsubscribe(sub_id)

C++

cpp
QObject::connect(&client, &vericue::VeriCueClient::eventReceived,
    [](const QString &subId, const QString &event,
       const QString &path, const QJsonObject &data) {
        qInfo() << event << "on" << path << ":" << data;
    });

client.subscribeSignal("MainWindow/okButton", "clicked");

C#

csharp
string subId = await client.SubscribeSignalAsync(
    "MainWindow/okButton", "clicked");

// Single await with timeout
var evt = await client.NextEventAsync(TimeSpan.FromSeconds(5));

// Or async-stream
await foreach (var e in client.EventsAsync(ct))
    Console.WriteLine($"{e.EventName} on {e.Path}");

// Or callback at subscribe time
await client.SubscribeSignalAsync(
    "MainWindow/dropZone", "fileDropped",
    callback: e => Console.WriteLine(e.Data));

Common patterns

Wait for "any of N" outcomes

wait_for_signal only handles one signal at a time. If your test waits for any of "Success", "Failure", "Cancelled", subscribe to all three and use whichever event arrives first:

python
ok  = await client.subscribe_signal("MainWindow/dialog", "accepted")
err = await client.subscribe_signal("MainWindow/dialog", "rejected")
event = await client.next_event(timeout=10)
print("Got:", event["data"]["signal"])

Recording all events for a test

For diagnostics, subscribe to many signals and dump every event to a log file:

python
for path, sig in interesting_signals:
    await client.subscribe_signal(path, sig)

with open("events.jsonl", "w") as f:
    async for event in client.events():
        f.write(json.dumps(event) + "\n")

Released under a commercial licence. Privacy · Terms