feat(cluster): the spot list size is a setting
The list is a ring buffer that held a thousand spots, and on a busy evening a thousand arrive in a couple of minutes. So the buffer decided how long a spot lived, and the spot LIFETIME setting never got the chance to expire anything: fifteen minutes meant nothing when the oldest spot was pushed out after two. Now settable (Preferences → Cluster, beside the lifetime, since between them they decide the same thing), 100 to 10 000. The ceiling is a real limit rather than a round number: every spot is matched against the worked index and the alert rules, and is a row the cluster grid and every open band map re-render.
This commit is contained in:
+15
-4
@@ -95,7 +95,7 @@ import { ShutdownProgress } from '@/components/ShutdownProgress';
|
||||
import { ClusterGrid } from '@/components/ClusterGrid';
|
||||
import { cleanSpotter, inferSpotMode, spotModeCategory, spotStatusKey } from '@/lib/spot';
|
||||
import { applySpotDisplay, readSpotDisplayOptions, spotIsWorked, SPOT_DISPLAY_OPTIONS_EXPOSED } from '@/lib/spotDisplay';
|
||||
import { AnswerDecode, HaltDecodeTx, LogUIError, FlexTXOnBand, GetMatrixColors, GetRotorPresets, GetRowColors, GetSpotTTLMinutes, IsNewUSCounty } from '../wailsjs/go/main/App';
|
||||
import { AnswerDecode, HaltDecodeTx, LogUIError, FlexTXOnBand, GetMatrixColors, GetRotorPresets, GetRowColors, GetSpotTTLMinutes, GetSpotMax, IsNewUSCounty } from '../wailsjs/go/main/App';
|
||||
import { applyMatrixColors } from '@/lib/matrixColors';
|
||||
import { WorkedBeforeGrid } from '@/components/WorkedBeforeGrid';
|
||||
import { NetControlPanel } from '@/components/NetControlPanel';
|
||||
@@ -1663,7 +1663,14 @@ export default function App() {
|
||||
const [clusterServers, setClusterServers] = useState<{ id: number; name: string; enabled: boolean; sort_order: number }[]>([]);
|
||||
// Ring buffer — only keep the last N spots; cluster firehose can be heavy.
|
||||
const [spots, setSpots] = useState<ClusterSpot[]>([]);
|
||||
const SPOTS_CAP = 1000;
|
||||
// How many spots the list holds. A setting rather than a constant: at a
|
||||
// thousand, a busy evening filled the buffer in a couple of minutes, so the
|
||||
// spot LIFETIME never had anything left to expire — the cap was deciding the
|
||||
// lifetime. Kept in a ref as well: the append path runs inside a state updater
|
||||
// that must not close over a stale value.
|
||||
const [spotsCap, setSpotsCap] = useState(1000);
|
||||
const spotsCapRef = useRef(1000);
|
||||
useEffect(() => { spotsCapRef.current = spotsCap; }, [spotsCap]);
|
||||
// Cluster filter selections persist across restarts (writeUiPref → localStorage
|
||||
// + DB, so they also travel with a copied data/ folder). Loaders read the cache
|
||||
// synchronously at first render; a single effect below writes them back.
|
||||
@@ -1977,7 +1984,7 @@ export default function App() {
|
||||
useEffect(() => {
|
||||
setSpotStatus((prev) => {
|
||||
const keys = Object.keys(prev);
|
||||
if (keys.length <= SPOTS_CAP * 2) return prev;
|
||||
if (keys.length <= spotsCapRef.current * 2) return prev;
|
||||
const live = new Set(spots.map((x) => spotStatusKey(x.dx_call, x.band ?? '', x.comment ?? '', x.freq_hz)));
|
||||
// Decoded stations count as live too. They share this cache, and pruning
|
||||
// to the cluster spots alone would evict every one of them — on a busy
|
||||
@@ -2488,6 +2495,9 @@ export default function App() {
|
||||
// same thing everywhere — and it gives the memory back.
|
||||
const [spotTTLMin, setSpotTTLMin] = useState(0);
|
||||
useEffect(() => { GetSpotTTLMinutes().then(setSpotTTLMin).catch(() => {}); }, [showSettings]);
|
||||
// Same beat as the lifetime: re-read when Preferences closes, since the two
|
||||
// settings decide between them how long a spot survives.
|
||||
useEffect(() => { GetSpotMax().then((n: number) => { if (n > 0) setSpotsCap(n); }).catch(() => {}); }, [showSettings]);
|
||||
useEffect(() => {
|
||||
if (spotTTLMin <= 0) return; // 0 = keep until the count cap pushes them out
|
||||
const sweep = () => {
|
||||
@@ -3478,7 +3488,8 @@ export default function App() {
|
||||
const filtered = hist(sp) ? next : next.filter((x) => hist(x) || key(x) !== k);
|
||||
next = [sp, ...filtered];
|
||||
}
|
||||
return next.length > SPOTS_CAP ? next.slice(0, SPOTS_CAP) : next;
|
||||
const cap = spotsCapRef.current;
|
||||
return next.length > cap ? next.slice(0, cap) : next;
|
||||
});
|
||||
};
|
||||
const unsubSpot = EventsOn('cluster:spot', (sp: ClusterSpot) => {
|
||||
|
||||
Reference in New Issue
Block a user