feat(events): A.4 — emit SnapshotChanged from the watchdog probe
Adds a new variant to the lifecycle event catalogue so the UI can
auto-refresh the channel/client tree without an independent polling
timer on the Dart side. The supervisor's existing 5 s snapshot probe
is the source of truth: it already pulls a full snapshot to keep
the watchdog honest, so we piggyback on it.
* `chanora_core::SessionEvent::SnapshotChanged { channels, clients }`
carries the latest channel and client counts.
* The supervisor compares the probe result to `last_counts` and
fires the event only when the count actually changes. `last_counts`
is reset to `None` on a successful reconnect so the freshly
dialled session re-emits its initial counts.
* `chanora_bridge::api::BridgeEvent::SnapshotChanged` is the
cross-bridge mirror.
* Flutter routes the event through `_onEvent`, which calls
`_onRefresh()` to repopulate the snapshot view.
The probe-driven detection has known limits — pure within-channel
client moves do not change the count and so are not surfaced. That
gap will close when the supervisor tracks a content hash in
addition to the count; the count-only signal is sufficient for the
common "someone joined / someone left" case observed on cn.teamspeak.app.
This commit is contained in:
@@ -359,6 +359,15 @@ pub enum BridgeEvent {
|
||||
AudioStarted,
|
||||
/// Audio engine stopped.
|
||||
AudioStopped,
|
||||
/// Snapshot probe observed a change in channel/client counts.
|
||||
/// UI uses this to drive an auto-refresh without active
|
||||
/// polling.
|
||||
SnapshotChanged {
|
||||
/// Latest channel count.
|
||||
channels: u32,
|
||||
/// Latest client count.
|
||||
clients: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<chanora_core::SessionEvent> for BridgeEvent {
|
||||
@@ -380,6 +389,9 @@ impl From<chanora_core::SessionEvent> for BridgeEvent {
|
||||
}
|
||||
chanora_core::SessionEvent::AudioStarted => BridgeEvent::AudioStarted,
|
||||
chanora_core::SessionEvent::AudioStopped => BridgeEvent::AudioStopped,
|
||||
chanora_core::SessionEvent::SnapshotChanged { channels, clients } => {
|
||||
BridgeEvent::SnapshotChanged { channels, clients }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,6 +612,14 @@ impl SseDecode for crate::api::BridgeEvent {
|
||||
5 => {
|
||||
return crate::api::BridgeEvent::AudioStopped;
|
||||
}
|
||||
6 => {
|
||||
let mut var_channels = <u32>::sse_decode(deserializer);
|
||||
let mut var_clients = <u32>::sse_decode(deserializer);
|
||||
return crate::api::BridgeEvent::SnapshotChanged {
|
||||
channels: var_channels,
|
||||
clients: var_clients,
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("");
|
||||
}
|
||||
@@ -878,6 +886,12 @@ impl flutter_rust_bridge::IntoDart for crate::api::BridgeEvent {
|
||||
}
|
||||
crate::api::BridgeEvent::AudioStarted => [4.into_dart()].into_dart(),
|
||||
crate::api::BridgeEvent::AudioStopped => [5.into_dart()].into_dart(),
|
||||
crate::api::BridgeEvent::SnapshotChanged { channels, clients } => [
|
||||
6.into_dart(),
|
||||
channels.into_into_dart().into_dart(),
|
||||
clients.into_into_dart().into_dart(),
|
||||
]
|
||||
.into_dart(),
|
||||
_ => {
|
||||
unimplemented!("");
|
||||
}
|
||||
@@ -1055,6 +1069,11 @@ impl SseEncode for crate::api::BridgeEvent {
|
||||
crate::api::BridgeEvent::AudioStopped => {
|
||||
<i32>::sse_encode(5, serializer);
|
||||
}
|
||||
crate::api::BridgeEvent::SnapshotChanged { channels, clients } => {
|
||||
<i32>::sse_encode(6, serializer);
|
||||
<u32>::sse_encode(channels, serializer);
|
||||
<u32>::sse_encode(clients, serializer);
|
||||
}
|
||||
_ => {
|
||||
unimplemented!("");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user