MCPcopy Create free account
hub / github.com/aethersdr/AetherSDR / doStreams

Method doStreams

src/core/AutomationServer.cpp:4113–4224  ·  view source on GitHub ↗

── Radio-side display-stream inventory / leak detector (#3856) ────────────── `get pans` can never show a radio-side leak: the client tears down its own view on the "removed" echo, so it always looks clean. This verb reports two independent radio-authoritative views: Layer A (`streams`) — VITA-49 UDP truth: streams the radio is STILL transmitting for an id we no longer own (catches continued-

Source from the content-addressed store, hash-verified

4111// resource-level lingering that emits no UDP (#3843).
4112// `streams reset` clears the Layer-A orphan tally to re-baseline a before/after.
4113QJsonObject AutomationServer::doStreams(const QString& action)
4114{
4115 if (!m_radioModel)
4116 return err(QStringLiteral("no radio model available"));
4117
4118 const auto hex = [](quint32 id) {
4119 return QStringLiteral("0x") + QString::number(id, 16);
4120 };
4121 const auto ownStr = [](DisplayInventory::Ownership o) {
4122 switch (o) {
4123 case DisplayInventory::Ownership::Ours: return QStringLiteral("ours");
4124 case DisplayInventory::Ownership::Foreign: return QStringLiteral("foreign");
4125 default: return QStringLiteral("orphan");
4126 }
4127 };
4128
4129 // Layer B — radio-authoritative display-object inventory.
4130 if (action.compare(QLatin1String("radio"), Qt::CaseInsensitive) == 0
4131 || action.compare(QLatin1String("inventory"), Qt::CaseInsensitive) == 0) {
4132 const DisplayInventory::Report rep = m_radioModel->displayInventoryReport();
4133 QJsonArray pans;
4134 for (const auto& p : rep.pans)
4135 pans.append(QJsonObject{{QStringLiteral("panId"), p.id},
4136 {QStringLiteral("clientHandle"), hex(p.clientHandle)},
4137 {QStringLiteral("ownership"), ownStr(p.ownership)}});
4138 QJsonArray wfs;
4139 for (const auto& w : rep.waterfalls) {
4140 QJsonObject o{{QStringLiteral("waterfallId"), w.id},
4141 {QStringLiteral("clientHandle"), hex(w.clientHandle)},
4142 {QStringLiteral("ownership"), ownStr(w.ownership)},
4143 {QStringLiteral("parentMissing"), w.parentMissing}};
4144 if (!w.parentPanId.isEmpty())
4145 o[QStringLiteral("parentPanId")] = w.parentPanId;
4146 wfs.append(o);
4147 }
4148 QJsonArray leaked;
4149 for (const auto& id : rep.leakedWaterfalls) leaked.append(id);
4150 return QJsonObject{
4151 {QStringLiteral("ok"), true},
4152 {QStringLiteral("scope"), QStringLiteral("radio")},
4153 {QStringLiteral("pans"), pans},
4154 {QStringLiteral("waterfalls"), wfs},
4155 {QStringLiteral("radioPanCount"), rep.pans.size()},
4156 {QStringLiteral("radioWaterfallCount"), rep.waterfalls.size()},
4157 {QStringLiteral("orphanPanCount"), rep.orphanPanCount},
4158 {QStringLiteral("orphanWaterfallCount"), rep.orphanWfCount},
4159 {QStringLiteral("foreignPanCount"), rep.foreignPanCount},
4160 {QStringLiteral("foreignWaterfallCount"), rep.foreignWfCount},
4161 {QStringLiteral("leakedWaterfalls"), leaked},
4162 {QStringLiteral("leakCount"), leaked.size()},
4163 };
4164 }
4165
4166 // `streams resync` — force the radio to re-dump its authoritative display
4167 // set, then re-poll `streams radio` after a moment. Closes the gap where a
4168 // waterfall lingers as a radio resource but no longer emits UDP (Layer A
4169 // can't see it) and the client already purged its view (Layer B looked
4170 // clean). The re-dump is async, so this just triggers and the driver reads

Callers

nothing calls this directly

Calls 11

errFunction · 0.85
hexFunction · 0.85
panStreamMethod · 0.80
resetOrphanStreamsMethod · 0.80
registeredPanStreamsMethod · 0.80
registeredWfStreamsMethod · 0.80
orphanStreamsMethod · 0.80
isEmptyMethod · 0.45
sizeMethod · 0.45

Tested by

no test coverage detected