[fix](trx-frontend-http): buffer decode messages until map-data plugins are ready

Eagerly load map-data plugins (AIS, APRS, VDES, HF-APRS) on startup and
buffer any decode history or live SSE messages that arrive before plugin
handlers register. Each plugin drains its pending buffer on init.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-04-04 12:08:18 +02:00
parent f978812090
commit 79068e55af
6 changed files with 65 additions and 14 deletions
@@ -563,6 +563,41 @@ const decodeHistoryTextDecoder = typeof TextDecoder === "function" ? new TextDec
let decodeHistoryReplayActive = false;
let decodeMapSyncPending = false;
// --- Pending decode data buffers ---
// Map-data plugins (ais.js, aprs.js, vdes.js, hf-aprs.js) are loaded eagerly
// but dynamically-inserted scripts have no guaranteed execution order. If
// decode history or live SSE messages arrive before the plugin handlers are
// registered, buffer them here and let each plugin drain on init.
const _pendingDecodeHistory = {};
const _pendingDecodeLive = {};
window._trxDrainPendingDecode = function(kind) {
const historyKey = {
ais: "restoreAisHistory",
vdes: "restoreVdesHistory",
aprs: "restoreAprsHistory",
hf_aprs: "restoreHfAprsHistory",
}[kind];
if (historyKey && _pendingDecodeHistory[kind] && window[historyKey]) {
const msgs = _pendingDecodeHistory[kind];
delete _pendingDecodeHistory[kind];
window[historyKey](msgs);
}
const liveKey = {
ais: "onServerAis",
vdes: "onServerVdes",
aprs: "onServerAprs",
hf_aprs: "onServerHfAprs",
}[kind];
if (liveKey && _pendingDecodeLive[kind] && window[liveKey]) {
const msgs = _pendingDecodeLive[kind];
delete _pendingDecodeLive[kind];
for (const msg of msgs) {
try { window[liveKey](msg); } catch (_) {}
}
}
};
function markDecodeMapSyncPending() {
decodeMapSyncPending = true;
}
@@ -5920,10 +5955,10 @@ function updateDecodeStatus(text) {
}
}
function dispatchDecodeMessage(msg, skipStats) {
if (msg.type === "ais" && window.onServerAis) window.onServerAis(msg);
if (msg.type === "vdes" && window.onServerVdes) window.onServerVdes(msg);
if (msg.type === "aprs" && window.onServerAprs) window.onServerAprs(msg);
if (msg.type === "hf_aprs" && window.onServerHfAprs) window.onServerHfAprs(msg);
if (msg.type === "ais") { if (window.onServerAis) window.onServerAis(msg); else (_pendingDecodeLive.ais = _pendingDecodeLive.ais || []).push(msg); }
if (msg.type === "vdes") { if (window.onServerVdes) window.onServerVdes(msg); else (_pendingDecodeLive.vdes = _pendingDecodeLive.vdes || []).push(msg); }
if (msg.type === "aprs") { if (window.onServerAprs) window.onServerAprs(msg); else (_pendingDecodeLive.aprs = _pendingDecodeLive.aprs || []).push(msg); }
if (msg.type === "hf_aprs") { if (window.onServerHfAprs) window.onServerHfAprs(msg); else (_pendingDecodeLive.hf_aprs = _pendingDecodeLive.hf_aprs || []).push(msg); }
if (msg.type === "cw" && window.onServerCw) window.onServerCw(msg);
if (msg.type === "ft8" && window.onServerFt8) window.onServerFt8(msg);
if (msg.type === "ft4" && window.onServerFt4) window.onServerFt4(msg);
@@ -6036,20 +6071,24 @@ function restoreDecodeHistoryGroup(kind, messages) {
}
window.trx.map?.scheduleStatsRender();
}
if (kind === "ais" && window.restoreAisHistory) {
window.restoreAisHistory(messages);
if (kind === "ais") {
if (window.restoreAisHistory) { window.restoreAisHistory(messages); }
else { _pendingDecodeHistory.ais = (_pendingDecodeHistory.ais || []).concat(messages); }
return;
}
if (kind === "vdes" && window.restoreVdesHistory) {
window.restoreVdesHistory(messages);
if (kind === "vdes") {
if (window.restoreVdesHistory) { window.restoreVdesHistory(messages); }
else { _pendingDecodeHistory.vdes = (_pendingDecodeHistory.vdes || []).concat(messages); }
return;
}
if (kind === "aprs" && window.restoreAprsHistory) {
window.restoreAprsHistory(messages);
if (kind === "aprs") {
if (window.restoreAprsHistory) { window.restoreAprsHistory(messages); }
else { _pendingDecodeHistory.aprs = (_pendingDecodeHistory.aprs || []).concat(messages); }
return;
}
if (kind === "hf_aprs" && window.restoreHfAprsHistory) {
window.restoreHfAprsHistory(messages);
if (kind === "hf_aprs") {
if (window.restoreHfAprsHistory) { window.restoreHfAprsHistory(messages); }
else { _pendingDecodeHistory.hf_aprs = (_pendingDecodeHistory.hf_aprs || []).concat(messages); }
return;
}
if (kind === "cw" && window.restoreCwHistory) {
@@ -6083,6 +6122,9 @@ function connectDecode() {
terminateDecodeHistoryWorker();
decodeHistoryReplayActive = false;
decodeMapSyncPending = false;
// Clear any pending buffers from a previous connection cycle.
for (const k in _pendingDecodeHistory) delete _pendingDecodeHistory[k];
for (const k in _pendingDecodeLive) delete _pendingDecodeLive[k];
if (window.resetAisHistoryView) window.resetAisHistoryView();
if (window.resetVdesHistoryView) window.resetVdesHistoryView();
if (window.resetAprsHistoryView) window.resetAprsHistoryView();