Fix realistic mode: all WS broadcasts include hash + raw_hex

Secondary broadcast paths (ADVERT, GRP_TXT, TXT_MSG, TRACE, API)
were missing hash field. Without hash, realistic mode's buffer
check (if pkt.hash) failed and packets fell through to
animatePacket individually — causing duplicate feed items and
duplicate sonification.

Also added missing addFeedItem call in animateRealisticPropagation
so the feed shows consolidated entries in realistic mode.
This commit is contained in:
you
2026-03-22 18:37:53 +00:00
parent 4e8b1b2584
commit 90bd9e12e5
3 changed files with 10 additions and 7 deletions

View File

@@ -92,7 +92,7 @@
<script src="analytics.js?v=1774126708" onerror="console.error('Failed to load:', this.src)"></script>
<script src="audio.js?v=1774200683" onerror="console.error('Failed to load:', this.src)"></script>
<script src="audio-v1-constellation.js?v=1774204296" onerror="console.error('Failed to load:', this.src)"></script>
<script src="live.js?v=1774203115" onerror="console.error('Failed to load:', this.src)"></script>
<script src="live.js?v=1774204673" onerror="console.error('Failed to load:', this.src)"></script>
<script src="observers.js?v=1774290000" onerror="console.error('Failed to load:', this.src)"></script>
<script src="observer-detail.js?v=1774028201" onerror="console.error('Failed to load:', this.src)"></script>
<script src="node-analytics.js?v=1774126708" onerror="console.error('Failed to load:', this.src)"></script>

View File

@@ -1470,6 +1470,9 @@
if (showOnlyFavorites && !packets.some(p => packetInvolvesFavorite(p))) return;
if (window.MeshAudio) MeshAudio.sonifyPacket(first);
// Add single consolidated feed item for the group
const allHops = (decoded.path?.hops) || [];
addFeedItem(icon, typeName, payload, allHops, color, Object.assign({}, first, { observation_count: packets.length }));
// Rain drop per observation in the group
packets.forEach((p, i) => setTimeout(() => addRainDrop(p), i * 150));

View File

@@ -796,7 +796,7 @@ for (const source of mqttSources) {
};
const packetId = pktStore.insert(advertPktData); _updateHashSizeForPacket(advertPktData);
try { db.insertTransmission(advertPktData); } catch (e) { console.error('[dual-write] transmission insert error:', e.message); }
broadcast({ type: 'packet', data: { id: packetId, decoded: { header: { payloadTypeName: 'ADVERT' }, payload: advert } } });
broadcast({ type: 'packet', data: { id: packetId, hash: advertPktData.hash, raw: advertPktData.raw_hex, decoded: { header: { payloadTypeName: 'ADVERT' }, payload: advert } } });
}
return;
}
@@ -829,8 +829,8 @@ for (const source of mqttSources) {
};
const packetId = pktStore.insert(chPktData); _updateHashSizeForPacket(chPktData);
try { db.insertTransmission(chPktData); } catch (e) { console.error('[dual-write] transmission insert error:', e.message); }
broadcast({ type: 'packet', data: { id: packetId, decoded: { header: { payloadTypeName: 'GRP_TXT' }, payload: channelMsg } } });
broadcast({ type: 'message', data: { id: packetId, decoded: { header: { payloadTypeName: 'GRP_TXT' }, payload: channelMsg } } });
broadcast({ type: 'packet', data: { id: packetId, hash: chPktData.hash, raw: chPktData.raw_hex, decoded: { header: { payloadTypeName: 'GRP_TXT' }, payload: channelMsg } } });
broadcast({ type: 'message', data: { id: packetId, hash: chPktData.hash, decoded: { header: { payloadTypeName: 'GRP_TXT' }, payload: channelMsg } } });
return;
}
@@ -852,7 +852,7 @@ for (const source of mqttSources) {
};
const packetId = pktStore.insert(dmPktData); _updateHashSizeForPacket(dmPktData);
try { db.insertTransmission(dmPktData); } catch (e) { console.error('[dual-write] transmission insert error:', e.message); }
broadcast({ type: 'packet', data: { id: packetId, decoded: { header: { payloadTypeName: 'TXT_MSG' }, payload: dm } } });
broadcast({ type: 'packet', data: { id: packetId, hash: dmPktData.hash, raw: dmPktData.raw_hex, decoded: { header: { payloadTypeName: 'TXT_MSG' }, payload: dm } } });
return;
}
@@ -874,7 +874,7 @@ for (const source of mqttSources) {
};
const packetId = pktStore.insert(tracePktData); _updateHashSizeForPacket(tracePktData);
try { db.insertTransmission(tracePktData); } catch (e) { console.error('[dual-write] transmission insert error:', e.message); }
broadcast({ type: 'packet', data: { id: packetId, decoded: { header: { payloadTypeName: 'TRACE' }, payload: trace } } });
broadcast({ type: 'packet', data: { id: packetId, hash: tracePktData.hash, raw: tracePktData.raw_hex, decoded: { header: { payloadTypeName: 'TRACE' }, payload: trace } } });
return;
}
@@ -1112,7 +1112,7 @@ app.post('/api/packets', requireApiKey, (req, res) => {
// Invalidate caches on new data
cache.debouncedInvalidateAll();
broadcast({ type: 'packet', data: { id: packetId, decoded } });
broadcast({ type: 'packet', data: { id: packetId, hash: apiPktData.hash, raw: apiPktData.raw_hex, decoded } });
res.json({ id: packetId, decoded });
} catch (e) {