mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 03:14:00 +00:00
fix(street-level): KartaView round-2 follow-ups — context loss, size cap, slow lookups
From the second IC8 pass (launch ready; P3s closed here): - A lost WebGL context is redrawn on a new canvas (the old one only gives back its lost context), through the core, and only if no newer photo is opening; verified live with WEBGL_lose_context, twice. - The 16 MB answer cap counts bytes while reading: KartaView sends chunked answers with no Content-Length, so the header check never fired. - A lookup gets 8 s, then 15 s once more: KartaView sometimes sits on a lookup for 11 s and answers the same one in 3 s. Left as follow-ups: cancelling abandoned sequence pages; finding a page by binary search on the index when thousands of photos are missing. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
0394a9b908
commit
97a1a667de
7 files changed
+158
-24
No files matched your search
@@ -10,6 +10,7 @@ import {
|
||||
PHOTO_API_RETRIES,
|
||||
PHOTO_API_RETRY_BASE_MS,
|
||||
PHOTO_API_RETRY_MAX_MS,
|
||||
PHOTO_API_FIRST_TIMEOUT_MS,
|
||||
PHOTO_API_TIMEOUT_MS,
|
||||
TILE_CONCURRENCY,
|
||||
TILE_TIMEOUT_MS,
|
||||
@@ -144,11 +145,33 @@ export function createKartaViewSource({
|
||||
{ status: response.status },
|
||||
);
|
||||
const length = Number(response.headers?.get?.('content-length'));
|
||||
if (length > MAX_RESPONSE_BYTES)
|
||||
throw new KartaViewSourceError('KartaView sent too much data', {
|
||||
const tooMuch = () =>
|
||||
new KartaViewSourceError('KartaView sent too much data', {
|
||||
status: response.status,
|
||||
});
|
||||
return await response.json();
|
||||
if (length > MAX_RESPONSE_BYTES) throw tooMuch();
|
||||
// KartaView answers chunked, without a length: count while reading.
|
||||
const reader = response.body?.getReader?.();
|
||||
if (!reader) return await response.json();
|
||||
const chunks = [];
|
||||
let bytes = 0;
|
||||
for (;;) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
bytes += value.byteLength;
|
||||
if (bytes > MAX_RESPONSE_BYTES) {
|
||||
reader.cancel().catch(() => {});
|
||||
throw tooMuch();
|
||||
}
|
||||
chunks.push(value);
|
||||
}
|
||||
const body = new Uint8Array(bytes);
|
||||
let offset = 0;
|
||||
for (const chunk of chunks) {
|
||||
body.set(chunk, offset);
|
||||
offset += chunk.byteLength;
|
||||
}
|
||||
return JSON.parse(new TextDecoder().decode(body));
|
||||
} catch (error) {
|
||||
if (signal?.aborted) throw signal.reason;
|
||||
if (controller.signal.aborted) throw controller.signal.reason;
|
||||
@@ -168,7 +191,11 @@ export function createKartaViewSource({
|
||||
path,
|
||||
params,
|
||||
{ signal } = {},
|
||||
{ gate = limiter, timeoutMs = PHOTO_API_TIMEOUT_MS } = {},
|
||||
{
|
||||
gate = limiter,
|
||||
timeoutMs = PHOTO_API_TIMEOUT_MS,
|
||||
firstTimeoutMs = PHOTO_API_FIRST_TIMEOUT_MS,
|
||||
} = {},
|
||||
) {
|
||||
const query = params ? `?${new URLSearchParams(params)}` : '';
|
||||
const url = `${apiHost}${path}${query}`;
|
||||
@@ -176,7 +203,12 @@ export function createKartaViewSource({
|
||||
for (let attempt = 0; ; attempt++) {
|
||||
try {
|
||||
const payload = await gate.run(
|
||||
() => getJson(url, { signal, timeoutMs }),
|
||||
// A slow first answer is usually quick when asked again.
|
||||
() =>
|
||||
getJson(url, {
|
||||
signal,
|
||||
timeoutMs: timeouts === 0 ? firstTimeoutMs : timeoutMs,
|
||||
}),
|
||||
{ signal },
|
||||
);
|
||||
const code = Number(payload?.status?.apiCode);
|
||||
@@ -300,7 +332,11 @@ export function createKartaViewSource({
|
||||
`/2.0/sequence/${encodeURIComponent(sequenceId)}/photos`,
|
||||
{ page: String(page), itemsPerPage: String(itemsPerPage) },
|
||||
{ signal },
|
||||
{ gate: pageLimiter, timeoutMs: PAGE_TIMEOUT_MS },
|
||||
{
|
||||
gate: pageLimiter,
|
||||
timeoutMs: PAGE_TIMEOUT_MS,
|
||||
firstTimeoutMs: PAGE_TIMEOUT_MS,
|
||||
},
|
||||
);
|
||||
return {
|
||||
photos: Array.isArray(result.data) ? result.data : [],
|
||||
|
||||
Reference in new issue
Block a user