mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-11 13:52:19 +00:00
End the data startup wait when the application is torn down during a slow layer attachment
This commit is contained in:
1 parent
7fb11507d5
commit
cf6d04b7db
2 files changed
+85
-15
No files matched your search
@@ -256,3 +256,45 @@ test('a catalog for an engine gives stand-ins only for the layers it leaves out'
|
|||||||
/Control layer missing from catalog: traffic/,
|
/Control layer missing from catalog: traffic/,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('a teardown during startup ends the wait for a stalled layer attachment', async (t) => {
|
||||||
|
const previous = globalThis.document;
|
||||||
|
globalThis.document = { getElementById: () => null };
|
||||||
|
t.after(() => {
|
||||||
|
if (previous === undefined) delete globalThis.document;
|
||||||
|
else globalThis.document = previous;
|
||||||
|
});
|
||||||
|
const layer = {
|
||||||
|
id: 'slow',
|
||||||
|
init: () => true,
|
||||||
|
enable: () => true,
|
||||||
|
update: () => true,
|
||||||
|
disable: () => true,
|
||||||
|
destroy: () => true,
|
||||||
|
attachRenderer: (viewer) =>
|
||||||
|
viewer?.second ? new Promise(() => {}) : undefined,
|
||||||
|
detachRenderer() {},
|
||||||
|
};
|
||||||
|
const layerSession = { lifetime: new AbortController() };
|
||||||
|
const start = (viewer, signal = null) => {
|
||||||
|
const releases = [];
|
||||||
|
const data = createApplicationData({
|
||||||
|
scene: { viewer },
|
||||||
|
controls: { styleManager: { attachDataManager() {} } },
|
||||||
|
catalog: createLayerCatalog([layer], metadata([layer])),
|
||||||
|
layerSession,
|
||||||
|
signal,
|
||||||
|
defer: (release) => releases.push(release),
|
||||||
|
});
|
||||||
|
return { data, releases };
|
||||||
|
};
|
||||||
|
const first = start({ first: true });
|
||||||
|
assert.equal(await layerSession.manager.setEnabled('slow', true), true);
|
||||||
|
for (const release of first.releases.reverse()) await release();
|
||||||
|
|
||||||
|
const application = new AbortController();
|
||||||
|
const second = start({ second: true }, application.signal);
|
||||||
|
application.abort();
|
||||||
|
const { dataManager } = await second.data;
|
||||||
|
assert.equal(dataManager, layerSession.manager);
|
||||||
|
});
|
||||||
+43
-15
@@ -11,17 +11,20 @@ export function createApplicationData({
|
|||||||
layerSession,
|
layerSession,
|
||||||
onData,
|
onData,
|
||||||
defer,
|
defer,
|
||||||
|
signal = null,
|
||||||
}) {
|
}) {
|
||||||
// Initialize data layer manager
|
// Initialize data layer manager
|
||||||
// The modules get { signal, engine } on every call (viewer null on Navara).
|
// The modules get { signal, engine } on every call (viewer null on Navara).
|
||||||
const dataManager = layerSession?.manager ?? new LayerLifecycle(viewer, {
|
const dataManager =
|
||||||
engine,
|
layerSession?.manager ??
|
||||||
allowQaRegistration,
|
new LayerLifecycle(viewer, {
|
||||||
// A panel's host may report it hidden while it is on screen; its layers
|
engine,
|
||||||
// keep polling (see keepPanelRendering in embed.js).
|
allowQaRegistration,
|
||||||
visibilityTarget: panelAwareVisibility(document),
|
// A panel's host may report it hidden while it is on screen; its layers
|
||||||
getSourceAvailability: catalog?.getSourceAvailability,
|
// keep polling (see keepPanelRendering in embed.js).
|
||||||
});
|
visibilityTarget: panelAwareVisibility(document),
|
||||||
|
getSourceAvailability: catalog?.getSourceAvailability,
|
||||||
|
});
|
||||||
if (layerSession) layerSession.manager = dataManager;
|
if (layerSession) layerSession.manager = dataManager;
|
||||||
defer(async () => {
|
defer(async () => {
|
||||||
if (layerSession && !layerSession.lifetime.signal.aborted) {
|
if (layerSession && !layerSession.lifetime.signal.aborted) {
|
||||||
@@ -34,12 +37,15 @@ export function createApplicationData({
|
|||||||
`Data layers could not be destroyed: ${[...dataManager.layers.keys()].join(', ')}`,
|
`Data layers could not be destroyed: ${[...dataManager.layers.keys()].join(', ')}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
const presentation = layerSession?.presentation ?? new LayerPresentation(dataManager, {
|
const presentation =
|
||||||
weatherClock: catalog?.weatherClock,
|
layerSession?.presentation ??
|
||||||
});
|
new LayerPresentation(dataManager, {
|
||||||
|
weatherClock: catalog?.weatherClock,
|
||||||
|
});
|
||||||
if (layerSession) layerSession.presentation = presentation;
|
if (layerSession) layerSession.presentation = presentation;
|
||||||
defer(() => {
|
defer(() => {
|
||||||
if (layerSession && !layerSession.lifetime.signal.aborted) presentation.suspend();
|
if (layerSession && !layerSession.lifetime.signal.aborted)
|
||||||
|
presentation.suspend();
|
||||||
else presentation.destroy();
|
else presentation.destroy();
|
||||||
});
|
});
|
||||||
onData?.(dataManager);
|
onData?.(dataManager);
|
||||||
@@ -47,7 +53,9 @@ export function createApplicationData({
|
|||||||
throw new TypeError('An application layer catalog is required');
|
throw new TypeError('An application layer catalog is required');
|
||||||
for (const layer of catalog.layers)
|
for (const layer of catalog.layers)
|
||||||
layer.attachMapStackController?.(mapStackController);
|
layer.attachMapStackController?.(mapStackController);
|
||||||
const attached = dataManager.bindCatalog(viewer, engine, catalog, { waitForCameraRestore: layerSession?.restoringView === true });
|
const attached = dataManager.bindCatalog(viewer, engine, catalog, {
|
||||||
|
waitForCameraRestore: layerSession?.restoringView === true,
|
||||||
|
});
|
||||||
for (const layer of catalog.layers) layer.attachDataManager?.(dataManager);
|
for (const layer of catalog.layers) layer.attachDataManager?.(dataManager);
|
||||||
|
|
||||||
if (allowQaRegistration) {
|
if (allowQaRegistration) {
|
||||||
@@ -70,11 +78,31 @@ export function createApplicationData({
|
|||||||
delete window.__gevQaUnregisterLayer;
|
delete window.__gevQaUnregisterLayer;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
presentation.mount(document.getElementById('data-toggles'), catalog.weatherClock);
|
presentation.mount(
|
||||||
|
document.getElementById('data-toggles'),
|
||||||
|
catalog.weatherClock,
|
||||||
|
);
|
||||||
styleManager.attachDataManager(dataManager);
|
styleManager.attachDataManager(dataManager);
|
||||||
// The sonar scene draws on the viewer; the Navara engine has none.
|
// The sonar scene draws on the viewer; the Navara engine has none.
|
||||||
if (viewer) defer(createCyberSonarScene(viewer, dataManager));
|
if (viewer) defer(createCyberSonarScene(viewer, dataManager));
|
||||||
|
|
||||||
const data = { dataManager, catalog, presentation };
|
const data = { dataManager, catalog, presentation };
|
||||||
return attached ? attached.then(() => data) : data;
|
if (!attached) return data;
|
||||||
|
// A teardown during startup must not wait for slow layer attachments: it
|
||||||
|
// ends this wait, and the data cleanup above releases the scene.
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const onAbort = () => resolve(data);
|
||||||
|
if (signal?.aborted) onAbort();
|
||||||
|
else signal?.addEventListener('abort', onAbort, { once: true });
|
||||||
|
attached.then(
|
||||||
|
() => {
|
||||||
|
signal?.removeEventListener('abort', onAbort);
|
||||||
|
resolve(data);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
signal?.removeEventListener('abort', onAbort);
|
||||||
|
reject(error);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user