[fix](trx-frontend-http): replay stored decodes onto the map when it loads
The map module is lazy: it arrives when the Map tab is first opened, which is normally long after startup restored the decode history. Until then aprsMapAddStation, aisMapAddVessel and vdesMapAddPoint are undefined, and the decoders' `if (lat != null && ... && fn)` guards quietly dropped every restored position. Nothing replayed them once the module did arrive, so the map came up empty and filled in only from decodes heard afterwards -- a station heard once was never plotted at all. A second reload appeared to fix it because the cached module then loaded early enough to win the race against the history fetch. Give DecoderPlugin an optional syncMap(), implement it for APRS, AIS and VDES over the history each already retains, and have map-core call trxPluginRuntime.syncMapAll() as it attaches. The add functions are keyed by callsign, MMSI and point, so replaying updates in place and cannot duplicate a marker; the replay runs oldest-first so tracks are rebuilt in the order they happened. Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -115,7 +115,8 @@ const historyFixture = await startWebFixture({
|
||||
aprs: Array.from({ length: HISTORY_APRS }, (_, index) => ({
|
||||
src_call: `SP2SJG-${index % 15}`, dest_call: "APRS", path: "WIDE1-1",
|
||||
info: `history ${index}`, packet_type: "position", crc_ok: true,
|
||||
lat: 54.3, lon: 18.6, rig_id: "rig-a", ts_ms: Date.now() - (index + 1) * 1000,
|
||||
lat: 54.3 + (index % 15) * 0.01, lon: 18.6, rig_id: "rig-a",
|
||||
ts_ms: Date.now() - (index + 1) * 1000,
|
||||
})),
|
||||
},
|
||||
});
|
||||
@@ -171,6 +172,33 @@ try {
|
||||
assert.equal(restored.aprs, HISTORY_APRS, `restored ${restored.aprs} of ${HISTORY_APRS} APRS records`);
|
||||
assert.equal(restored.progressHidden, true, "the progress stayed up after the replay finished");
|
||||
|
||||
// Opening the map for the first time has to show the stored history too.
|
||||
// The map module is lazy, so at the moment the history was restored its
|
||||
// aprsMapAddStation/aisMapAddVessel hooks did not exist yet and every
|
||||
// position was dropped. Nothing replayed them when the module finally
|
||||
// arrived, so the map came up empty and only filled in from decodes heard
|
||||
// afterwards -- a station heard once was never plotted at all, and it took a
|
||||
// second reload (module cached, so loaded early enough to beat the history
|
||||
// fetch) before the map showed anything.
|
||||
//
|
||||
// This fixture serves no live decode stream on purpose: with one, fresh
|
||||
// frames arriving after the module loads would paper over the whole thing.
|
||||
const mapLoadedDuringReplay = await replay.page.evaluate(() => !!window.trx.modules.map);
|
||||
assert.equal(mapLoadedDuringReplay, false, "the map was already loaded, so this proves nothing");
|
||||
|
||||
await replay.page.locator('.tab[data-tab="map"]').click();
|
||||
await replay.page.locator("#aprs-map .leaflet-pane").first().waitFor({ state: "attached" });
|
||||
await replay.page.waitForTimeout(1500);
|
||||
const plotted = await replay.page.evaluate(() => {
|
||||
const map = window.trx.modules.map;
|
||||
const size = (collection) => (collection instanceof Map
|
||||
? collection.size
|
||||
: Object.keys(collection ?? {}).length);
|
||||
return { ais: size(map?.aisMarkers), stations: size(map?.stationMarkers) };
|
||||
});
|
||||
assert.equal(plotted.ais, HISTORY_AIS, `${plotted.ais} of ${HISTORY_AIS} vessels reached the map`);
|
||||
assert.equal(plotted.stations, 15, `${plotted.stations} of 15 stations reached the map`);
|
||||
|
||||
assert.deepEqual(replay.runtimeErrors, []);
|
||||
} finally {
|
||||
await replay.browser.close();
|
||||
|
||||
Reference in New Issue
Block a user