[perf](trx-client): three quick-win optimizations
State deduplication via PartialEq + send_if_modified: Derive PartialEq on the full RigState / RigSnapshot type tree (Freq, Band, RigInfo, RigCapabilities, RigStatus, RigTxStatus, RigRxStatus, RigControl, RigVfo, RigVfoEntry, RigFilterState, RdsData, SpectrumData, RigState, RigSnapshot). Use state_tx.send_if_modified() in refresh_remote_snapshot() so WatchStream only wakes SSE /events subscribers when state actually changed; with a stable rig this eliminates ~1.3 spurious JSON serialisations per second per connected client. Cache-remote-rigs skip on unchanged list: cache_remote_rigs() was rebuilding the Vec and cloning every field on every 750 ms poll. Add a structural check (rig_id, display_name, initialized, audio_port) and return early when nothing has changed — the common steady-state case. RDS JSON pre-serialised at ingestion: SharedSpectrum.replace() now serialises the optional RDS object once and stores it alongside the Arc<SpectrumData> frame. Each /spectrum SSE client's 40 ms tick reads the cached string instead of calling serde_json::to_string() per-client per-tick. Add serde_json to trx-frontend Cargo.toml to support this. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -424,16 +424,13 @@ pub async fn spectrum(
|
||||
let next = context.spectrum.lock().ok().map(|g| g.snapshot());
|
||||
|
||||
let sse_chunk: Option<String> = match next {
|
||||
Some((revision, _frame)) if last_revision == Some(revision) => None,
|
||||
Some((revision, Some(frame))) => {
|
||||
Some((revision, _frame, _rds)) if last_revision == Some(revision) => None,
|
||||
Some((revision, Some(frame), rds_json)) => {
|
||||
last_revision = Some(revision);
|
||||
let mut chunk =
|
||||
format!("event: b\ndata: {}\n\n", encode_spectrum_frame(&frame));
|
||||
// Append an `rds` event only when the RDS payload changes.
|
||||
let rds_json = frame
|
||||
.rds
|
||||
.as_ref()
|
||||
.and_then(|r| serde_json::to_string(r).ok());
|
||||
// rds_json is pre-serialised at ingestion; append an
|
||||
// `rds` event only when the payload changed for this client.
|
||||
if rds_json != last_rds_json {
|
||||
let data = rds_json.as_deref().unwrap_or("null");
|
||||
chunk.push_str(&format!("event: rds\ndata: {data}\n\n"));
|
||||
@@ -441,7 +438,7 @@ pub async fn spectrum(
|
||||
}
|
||||
Some(chunk)
|
||||
}
|
||||
Some((revision, None)) => {
|
||||
Some((revision, None, _)) => {
|
||||
last_revision = Some(revision);
|
||||
Some("data: null\n\n".to_string())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user