mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
fix(weather): preserve enable during first-load replacement
This commit is contained in:
1 parent
de2138e84c
commit
0cb6857229
5 files changed
+80
-7
No files matched your search
@@ -1,5 +1,7 @@
|
|||||||
# God's Eye View Current State
|
# God's Eye View Current State
|
||||||
|
|
||||||
|
Wind and weather parameter changes may supersede a first-load request without rejecting the layer’s enable transaction. Obsolete responses cannot publish data; a replacement request remains visible through the loading state. Explicit caller cancellation, disable, and destroy still reject the obsolete update. Source failures continue to report their existing unavailable state.
|
||||||
|
|
||||||
Shared distance checks use `src/geoDistance.js` with `{ lat, lon }` points and
|
Shared distance checks use `src/geoDistance.js` with `{ lat, lon }` points and
|
||||||
the IUGG mean spherical Earth radius, 6371.0088 km. `greatCircleKm` is
|
the IUGG mean spherical Earth radius, 6371.0088 km. `greatCircleKm` is
|
||||||
canonical; `greatCircleMeters` is its exact metre conversion. Missing,
|
canonical; `greatCircleMeters` is its exact metre conversion. Missing,
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ export function createWeatherLayer({
|
|||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
});
|
});
|
||||||
if (!enabled || controller.signal.aborted || request !== controller)
|
if (!enabled || controller.signal.aborted || request !== controller)
|
||||||
return false;
|
return enabled && !signal?.aborted && request !== controller;
|
||||||
if (snapshot.unavailable) {
|
if (snapshot.unavailable) {
|
||||||
error = msg(
|
error = msg(
|
||||||
'Weather source unavailable; previous observation retained',
|
'Weather source unavailable; previous observation retained',
|
||||||
@@ -376,7 +376,9 @@ export function createWeatherLayer({
|
|||||||
)
|
)
|
||||||
await show(snapshot.latest, controller.signal);
|
await show(snapshot.latest, controller.signal);
|
||||||
return (
|
return (
|
||||||
!controller.signal.aborted && request === controller && enabled
|
enabled &&
|
||||||
|
!signal?.aborted &&
|
||||||
|
(!controller.signal.aborted || request !== controller)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const time =
|
const time =
|
||||||
@@ -388,9 +390,14 @@ export function createWeatherLayer({
|
|||||||
(satellite && rendering.getDiagnostics().infrared !== infrared)
|
(satellite && rendering.getDiagnostics().infrared !== infrared)
|
||||||
)
|
)
|
||||||
await show(time, controller.signal);
|
await show(time, controller.signal);
|
||||||
return !controller.signal.aborted && request === controller && enabled;
|
return (
|
||||||
|
enabled &&
|
||||||
|
!signal?.aborted &&
|
||||||
|
(!controller.signal.aborted || request !== controller)
|
||||||
|
);
|
||||||
} catch (cause) {
|
} catch (cause) {
|
||||||
if (controller.signal.aborted || request !== controller) return false;
|
if (controller.signal.aborted || request !== controller)
|
||||||
|
return enabled && !signal?.aborted && request !== controller;
|
||||||
error = cause?.message || msg('Weather unavailable');
|
error = cause?.message || msg('Weather unavailable');
|
||||||
stop();
|
stop();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -694,7 +694,11 @@ test('superseding a pending stage preserves the newer manifest loading state', a
|
|||||||
await flush();
|
await flush();
|
||||||
const newer = h.layer.update();
|
const newer = h.layer.update();
|
||||||
await flush();
|
await flush();
|
||||||
assert.equal(await old, false);
|
assert.equal(
|
||||||
|
await old,
|
||||||
|
true,
|
||||||
|
'replacement is accepted by the enable lifecycle',
|
||||||
|
);
|
||||||
assert.equal(
|
assert.equal(
|
||||||
h.layer.getStats().loading,
|
h.layer.getStats().loading,
|
||||||
true,
|
true,
|
||||||
@@ -2311,3 +2315,29 @@ for (const product of ['radar', 'clouds-regional', 'lightning']) {
|
|||||||
assert.equal(h.viewer.camera.moveEnd.size, 0);
|
assert.equal(h.viewer.camera.moveEnd.size, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test('a product replacement accepts supersession but never paints the obsolete first response', async () => {
|
||||||
|
const pending = [];
|
||||||
|
const h = layerHarness({
|
||||||
|
id: 'weather-satellite',
|
||||||
|
feed: {
|
||||||
|
getSnapshot: (args) => {
|
||||||
|
const task = deferred();
|
||||||
|
pending.push({ ...args, ...task });
|
||||||
|
return task.promise;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const first = h.layer.update();
|
||||||
|
h.layer.setParams({ product: 'clouds' });
|
||||||
|
assert.equal(pending.length, 2);
|
||||||
|
pending[0].resolve({ ...snapshot, product: 'clouds-regional' });
|
||||||
|
assert.equal(await first, true);
|
||||||
|
assert.equal(h.stages.length, 0);
|
||||||
|
pending[1].resolve({ ...snapshot, product: 'clouds' });
|
||||||
|
await flush();
|
||||||
|
h.stages.at(-1).finish();
|
||||||
|
await flush();
|
||||||
|
assert.equal(h.layer.getParams().product, 'clouds');
|
||||||
|
h.layer.destroy();
|
||||||
|
});
|
||||||
@@ -180,7 +180,7 @@ export function createWindLayer({
|
|||||||
overlay: requestedScalar(),
|
overlay: requestedScalar(),
|
||||||
});
|
});
|
||||||
if (!enabled || controller.signal.aborted || request !== controller)
|
if (!enabled || controller.signal.aborted || request !== controller)
|
||||||
return false;
|
return enabled && !signal?.aborted && request !== controller;
|
||||||
manifest = snapshot;
|
manifest = snapshot;
|
||||||
error = null;
|
error = null;
|
||||||
if (sampledPosition) sample(sampledPosition);
|
if (sampledPosition) sample(sampledPosition);
|
||||||
@@ -194,7 +194,8 @@ export function createWindLayer({
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (cause) {
|
} catch (cause) {
|
||||||
if (controller.signal.aborted || request !== controller) return false;
|
if (controller.signal.aborted || request !== controller)
|
||||||
|
return enabled && !signal?.aborted && request !== controller;
|
||||||
error = cause?.message || msg('Wind source unavailable');
|
error = cause?.message || msg('Wind source unavailable');
|
||||||
return true;
|
return true;
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -412,3 +412,36 @@ test('wind unit chips appear only alongside a speed legend, including canvas tra
|
|||||||
for (const overlay of ['pressure', 'temperature', 'none']) { layer.setParams({ overlay }); assert.deepEqual(unitChips(), []); }
|
for (const overlay of ['pressure', 'temperature', 'none']) { layer.setParams({ overlay }); assert.deepEqual(unitChips(), []); }
|
||||||
layer.destroy();
|
layer.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('a parameter replacement during manager enable does not roll the layer back', async () => {
|
||||||
|
const { LayerLifecycle } = await import('../../data/lifecycle.js');
|
||||||
|
const pending = [];
|
||||||
|
const rendering = Object.fromEntries(
|
||||||
|
['attach', 'start', 'stop', 'clear', 'destroy', 'setField'].map((name) => [
|
||||||
|
name,
|
||||||
|
() => {},
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
const layer = createWindLayer({
|
||||||
|
feed: {
|
||||||
|
getSnapshot: (args) =>
|
||||||
|
new Promise((resolve) => pending.push({ ...args, resolve })),
|
||||||
|
},
|
||||||
|
createRendering: () => rendering,
|
||||||
|
});
|
||||||
|
const manager = new LayerLifecycle({ container: {} });
|
||||||
|
manager.register(layer);
|
||||||
|
const enabled = manager.setEnabled('wind', true);
|
||||||
|
for (let i = 0; i < 20 && !pending.length; i++) await Promise.resolve();
|
||||||
|
layer.setParams({ model: 'ifs' });
|
||||||
|
await Promise.resolve();
|
||||||
|
pending[0].resolve(snapshot('gfs'));
|
||||||
|
assert.equal(await enabled, true);
|
||||||
|
assert.equal(manager.isEnabled('wind'), true);
|
||||||
|
assert.equal(layer.getStats().loading, true);
|
||||||
|
pending[1].resolve(snapshot('ifs'));
|
||||||
|
for (let i = 0; i < 10; i++) await Promise.resolve();
|
||||||
|
assert.equal(layer.getStats().model, 'IFS');
|
||||||
|
assert.equal(layer.getStats().count, 4);
|
||||||
|
await manager.destroyAll();
|
||||||
|
});
|
||||||
Reference in new issue
Block a user