From 90bd9e12e5fb9a46a5bb009a08816be80a2fe8a4 Mon Sep 17 00:00:00 2001 From: you Date: Sun, 22 Mar 2026 18:37:53 +0000 Subject: [PATCH] Fix realistic mode: all WS broadcasts include hash + raw_hex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- public/index.html | 2 +- public/live.js | 3 +++ server.js | 12 ++++++------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/public/index.html b/public/index.html index 55cb6ca..aa8c313 100644 --- a/public/index.html +++ b/public/index.html @@ -92,7 +92,7 @@ - + diff --git a/public/live.js b/public/live.js index 201fc55..66b4fc3 100644 --- a/public/live.js +++ b/public/live.js @@ -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)); diff --git a/server.js b/server.js index ae8e1b9..55623a5 100644 --- a/server.js +++ b/server.js @@ -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) {