mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
fix(street-level): release superseded and unmounted Google viewer work (#1117)
A superseded open wait cleared the shared cancelShown slot that belonged to the newer wait, leaving its auth listener and timer alive after close; open() now settles the previous wait first. A lookup whose viewer unmounted while the Street View service loaded still sent a billed getPanorama; describe() now rechecks the lookup after acquisition.
This commit is contained in:
1 parent
3c3ea269a9
commit
fb10889841
4 files changed
+76
-1
No files matched your search
@@ -0,0 +1,3 @@
|
||||
- Release superseded Google Street View open waits and suppress metadata
|
||||
requests whose viewer was unmounted while the service loaded (rudycelekli,
|
||||
#1117).
|
||||
@@ -3465,7 +3465,10 @@ controls (the address goes in the caption); a pose goes out at once and
|
||||
again when the panorama's month, photographer and address arrive (one
|
||||
successful lookup per panorama per session, seeded by the nearest lookup;
|
||||
a details lookup that fails or takes over ten seconds waits five seconds
|
||||
before a view event can retry, and an unmount drops lookups in flight). A key
|
||||
before a view event can retry, and an unmount drops lookups in flight). Opening
|
||||
another panorama settles the previous open before registering its wait; closing
|
||||
then releases the current wait immediately. A details lookup released while its
|
||||
service loads makes no panorama request after that service becomes available. A key
|
||||
Google refuses (`gm_authFailure`: the API not enabled, a referrer it does
|
||||
not allow, billing off) reads KEY REJECTED and fails a pending open at
|
||||
once; a lookup or open Google never answers fails after 10 or 20 s. In CI
|
||||
|
||||
@@ -97,6 +97,8 @@ export function createGoogleViewer({ loader, getService, render } = {}) {
|
||||
service ||= getService
|
||||
? await getService()
|
||||
: new (await ensureLibrary()).StreetViewService();
|
||||
if (!current())
|
||||
throw new Error('Street View details lookup was released');
|
||||
return service.getPanorama({ pano: panoId });
|
||||
})().then(resolve, reject);
|
||||
});
|
||||
@@ -236,6 +238,7 @@ export function createGoogleViewer({ loader, getService, render } = {}) {
|
||||
const panoId = String(imageId);
|
||||
if (!host) throw new Error('Street View is not mounted');
|
||||
if (loader.authFailed()) throw new Error(KEY_REJECTED_MESSAGE);
|
||||
cancelShown?.();
|
||||
pendingOpen = panoId;
|
||||
const instance = await ensurePanorama(host);
|
||||
if (pendingOpen !== panoId) return;
|
||||
|
||||
@@ -403,3 +403,69 @@ test('a remount looks up again a panorama whose lookup hung', async () => {
|
||||
await settle();
|
||||
assert.equal(poses.length, count);
|
||||
});
|
||||
|
||||
test('superseded panorama waits cannot steal the current close cleanup', async (t) => {
|
||||
t.mock.timers.enable({ apis: ['setTimeout'] });
|
||||
const { OPEN_TIMEOUT_MS } = await import('./policy.js');
|
||||
const flush = async () => {
|
||||
for (let i = 0; i < 10; i++) await Promise.resolve();
|
||||
};
|
||||
const { fake, loader, viewer, host } = setup();
|
||||
await viewer.mount(host);
|
||||
const [panorama] = fake.built;
|
||||
panorama.setPano = (id) => {
|
||||
panorama.pano = id;
|
||||
};
|
||||
const first = viewer.open('pano-a');
|
||||
await flush();
|
||||
const second = viewer.open('pano-b');
|
||||
await flush();
|
||||
panorama.fire('position_changed'); // new panorama has not reached OK
|
||||
await flush();
|
||||
viewer.close();
|
||||
const remaining = loader.listenerCount();
|
||||
t.mock.timers.tick(OPEN_TIMEOUT_MS);
|
||||
await Promise.allSettled([first, second]);
|
||||
assert.equal(
|
||||
remaining,
|
||||
0,
|
||||
'close disposes every pending open without waiting 20 seconds',
|
||||
);
|
||||
assert.equal(panorama.visible, false);
|
||||
});
|
||||
|
||||
test('unmount during details-service acquisition makes no later billed lookup', async () => {
|
||||
const fake = fakeStreetViewLibrary({ panoramas: PANORAMAS });
|
||||
const loader = fakeMapsLoader(fake.library);
|
||||
const { createGoogleProvider } = await import('./index.js');
|
||||
let release;
|
||||
const acquiring = new Promise((resolve) => {
|
||||
release = resolve;
|
||||
});
|
||||
const importLibrary = loader.importLibrary.bind(loader);
|
||||
let imports = 0;
|
||||
loader.importLibrary = async (name) => {
|
||||
if (++imports > 1) await acquiring;
|
||||
return importLibrary(name);
|
||||
};
|
||||
const provider = createGoogleProvider({
|
||||
getApiKey: () => 'fixture-key',
|
||||
loader,
|
||||
});
|
||||
const instance = provider.create({
|
||||
notify() {},
|
||||
actions: { reportError() {} },
|
||||
});
|
||||
const viewer = instance.viewer;
|
||||
await viewer.mount(fakeHost());
|
||||
await viewer.open('pano-a');
|
||||
viewer.unmount();
|
||||
release();
|
||||
for (let i = 0; i < 10; i++) await Promise.resolve();
|
||||
assert.equal(
|
||||
fake.lookups.length,
|
||||
0,
|
||||
'teardown invalidates the request before calling getPanorama',
|
||||
);
|
||||
instance.destroy();
|
||||
});
|
||||
Reference in new issue
Block a user