mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-08-25 11:52:32 +02:00
fix(layers): make restart repair passive and always-on
This commit is contained in:
@@ -94,10 +94,8 @@ export function getDefaultActiveLayers(): ActiveLayers {
|
||||
|
||||
const ACTIVE_LAYER_KEYS = Object.keys(getDefaultActiveLayers()) as (keyof ActiveLayers)[];
|
||||
const LAYER_BACKEND_SYNC_INTERVAL_MS = 5000;
|
||||
let layerBackendSyncTimer: ReturnType<typeof setInterval> | null = null;
|
||||
let layerBackendSyncTimer: number | null = null;
|
||||
let layerBackendSyncInFlight = false;
|
||||
let layerBackendSeenSuccess = false;
|
||||
let layerBackendSawFailure = false;
|
||||
let repairedDefaultBackendState = false;
|
||||
|
||||
function isBooleanRecord(value: unknown): value is Record<string, boolean> {
|
||||
@@ -199,10 +197,9 @@ function emitLayerPreferencesChanged(layers: ActiveLayers): void {
|
||||
* The dashboard already saves the operator's layer choices locally. The backend,
|
||||
* however, resets its fetcher gates on process restart. This reconciliation loop
|
||||
* observes the existing GET /api/layers endpoint and replays the saved operator
|
||||
* state only when a connection is first established, after an observed outage,
|
||||
* or when the backend has unmistakably fallen back to its shipped defaults.
|
||||
* It does not continuously overwrite arbitrary non-default server state, so two
|
||||
* independent clients do not get into a five-second preference tug-of-war.
|
||||
* state only when the backend is unmistakably back at its shipped defaults.
|
||||
* It deliberately leaves other non-default server state alone, so independent
|
||||
* clients do not get into a five-second preference tug-of-war.
|
||||
*/
|
||||
export async function reconcileActiveLayersWithBackend(): Promise<'synced' | 'noop' | 'offline'> {
|
||||
if (typeof window === 'undefined' || typeof fetch !== 'function') return 'offline';
|
||||
@@ -228,11 +225,7 @@ export async function reconcileActiveLayersWithBackend(): Promise<'synced' | 'no
|
||||
const backend = mergeActiveLayers(defaults, rawLayers);
|
||||
const mismatch = !layerMapsEqual(desired, backend);
|
||||
const backendAtDefaults = layerMapsEqual(backend, defaults);
|
||||
const shouldRepair =
|
||||
mismatch &&
|
||||
(!layerBackendSeenSuccess ||
|
||||
layerBackendSawFailure ||
|
||||
(backendAtDefaults && !repairedDefaultBackendState));
|
||||
const shouldRepair = mismatch && backendAtDefaults && !repairedDefaultBackendState;
|
||||
|
||||
if (shouldRepair) {
|
||||
const syncResponse = await fetch(`${API_BASE}/api/layers`, {
|
||||
@@ -245,18 +238,15 @@ export async function reconcileActiveLayersWithBackend(): Promise<'synced' | 'no
|
||||
}
|
||||
// useDataPolling already listens for this event and refreshes gated data immediately.
|
||||
window.dispatchEvent(new Event('sb:layer-toggle'));
|
||||
repairedDefaultBackendState = backendAtDefaults;
|
||||
layerBackendSeenSuccess = true;
|
||||
layerBackendSawFailure = false;
|
||||
repairedDefaultBackendState = true;
|
||||
return 'synced';
|
||||
}
|
||||
|
||||
// Once the repaired non-default state is observable, arm the watchdog for a
|
||||
// future backend restart that returns the process-local gate to defaults.
|
||||
if (!backendAtDefaults) repairedDefaultBackendState = false;
|
||||
layerBackendSeenSuccess = true;
|
||||
layerBackendSawFailure = false;
|
||||
return 'noop';
|
||||
} catch {
|
||||
layerBackendSawFailure = true;
|
||||
return 'offline';
|
||||
} finally {
|
||||
layerBackendSyncInFlight = false;
|
||||
@@ -352,3 +342,7 @@ export function loadLayerSectionExpanded(): Record<string, boolean> {
|
||||
export function saveLayerSectionExpanded(expanded: Record<string, boolean>): void {
|
||||
writeDashboardPrefs({ layerSectionsExpanded: expanded });
|
||||
}
|
||||
|
||||
// Start the passive restart watchdog as soon as the preferences module is loaded
|
||||
// in a real browser. SSR and Vitest are guarded inside ensureLayerBackendSync().
|
||||
ensureLayerBackendSync();
|
||||
|
||||
Reference in New Issue
Block a user