mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
fix: register data providers for local preview
Adapt the preview middleware contribution from PR #324 to the extracted provider modules, including the existing OpenSky route.
This commit is contained in:
1 parent
276bb84904
commit
a0f07b752f
10 files changed
+1100
-1089
No files matched your search
+116
-114
@@ -144,121 +144,123 @@ export function tomtomProxy() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
const installMiddleware = (server) => {
|
||||
server.middlewares.use('/api/tomtom', async (req, res) => {
|
||||
// Sanitized responses only (proxy/security baseline): no upstream
|
||||
// error details, and never echo the key or the upstream URL.
|
||||
const sendJson = (status, obj, extraHeaders = {}) => {
|
||||
if (res.headersSent) return;
|
||||
res.writeHead(status, {
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-store',
|
||||
...extraHeaders,
|
||||
});
|
||||
res.end(JSON.stringify(obj));
|
||||
};
|
||||
const sendTile = (buf, cacheStatus) => {
|
||||
if (res.headersSent) return;
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/x-protobuf',
|
||||
'Cache-Control': 'no-store',
|
||||
'x-tomtom-cache': cacheStatus,
|
||||
});
|
||||
res.end(buf);
|
||||
};
|
||||
|
||||
try {
|
||||
await loadBudgetOnce();
|
||||
const urlPath = String(req.url || '').split('?')[0];
|
||||
|
||||
if (urlPath === '/status') {
|
||||
const hasKey = Boolean(process.env.TOMTOM_API_KEY);
|
||||
const b = currentBudget();
|
||||
sendJson(200, {
|
||||
hasKey,
|
||||
dailyCount: b.count,
|
||||
budget: dailyBudgetLimit(),
|
||||
date: b.date,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const m = urlPath.match(/^\/flow\/(\d+)\/(\d+)\/(\d+)\.pbf$/);
|
||||
if (!m) {
|
||||
sendJson(404, { error: 'not_found' });
|
||||
return;
|
||||
}
|
||||
const z = Number(m[1]);
|
||||
const x = Number(m[2]);
|
||||
const y = Number(m[3]);
|
||||
if (!isValidTomTomTile(z, x, y)) {
|
||||
sendJson(400, { error: 'invalid_tile' });
|
||||
return;
|
||||
}
|
||||
if (!process.env.TOMTOM_API_KEY) {
|
||||
sendJson(503, { error: 'no_key' });
|
||||
return;
|
||||
}
|
||||
|
||||
const key = `${z}/${x}/${y}`;
|
||||
const now = Date.now();
|
||||
|
||||
let entry = mem.get(key);
|
||||
if (!entry) {
|
||||
entry = await readDiskTile(key);
|
||||
if (entry) memSet(key, entry);
|
||||
}
|
||||
// Fresh cache hit — never counts against the budget.
|
||||
if (entry && now - entry.at < TILE_TTL_MS) {
|
||||
sendTile(entry.buf, 'HIT');
|
||||
return;
|
||||
}
|
||||
|
||||
// Budget governor: over the soft cap, last-good data beats a dead layer.
|
||||
if (isTomTomOverBudget(currentBudget(), dailyBudgetLimit())) {
|
||||
if (entry) {
|
||||
sendTile(entry.buf, 'STALE-BUDGET');
|
||||
} else {
|
||||
sendJson(429, { error: 'budget' });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Stale or missing → refresh, single-flight per tile.
|
||||
if (!inflight.has(key)) {
|
||||
inflight.set(
|
||||
key,
|
||||
fetchUpstream(z, x, y)
|
||||
.then(async (buf) => {
|
||||
const fresh = { at: Date.now(), buf };
|
||||
memSet(key, fresh);
|
||||
await writeDiskTile(key, buf);
|
||||
return fresh;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn(
|
||||
`[tomtom-proxy] ${key} fetch failed (${err?.message || err}) — serving stale if any`,
|
||||
);
|
||||
return null;
|
||||
})
|
||||
.finally(() => inflight.delete(key)),
|
||||
);
|
||||
}
|
||||
const fresh = await inflight.get(key);
|
||||
if (fresh) {
|
||||
sendTile(fresh.buf, 'MISS');
|
||||
} else if (entry) {
|
||||
sendTile(entry.buf, 'STALE-ERROR'); // upstream down — stale beats empty
|
||||
} else {
|
||||
sendJson(502, { error: 'upstream' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[tomtom-proxy] error:', err?.message || err);
|
||||
sendJson(500, { error: 'proxy' });
|
||||
}
|
||||
});
|
||||
};
|
||||
return {
|
||||
name: 'tomtom-proxy',
|
||||
configureServer(server) {
|
||||
server.middlewares.use('/api/tomtom', async (req, res) => {
|
||||
// Sanitized responses only (proxy/security baseline): no upstream
|
||||
// error details, and never echo the key or the upstream URL.
|
||||
const sendJson = (status, obj, extraHeaders = {}) => {
|
||||
if (res.headersSent) return;
|
||||
res.writeHead(status, {
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-store',
|
||||
...extraHeaders,
|
||||
});
|
||||
res.end(JSON.stringify(obj));
|
||||
};
|
||||
const sendTile = (buf, cacheStatus) => {
|
||||
if (res.headersSent) return;
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/x-protobuf',
|
||||
'Cache-Control': 'no-store',
|
||||
'x-tomtom-cache': cacheStatus,
|
||||
});
|
||||
res.end(buf);
|
||||
};
|
||||
|
||||
try {
|
||||
await loadBudgetOnce();
|
||||
const urlPath = String(req.url || '').split('?')[0];
|
||||
|
||||
if (urlPath === '/status') {
|
||||
const hasKey = Boolean(process.env.TOMTOM_API_KEY);
|
||||
const b = currentBudget();
|
||||
sendJson(200, {
|
||||
hasKey,
|
||||
dailyCount: b.count,
|
||||
budget: dailyBudgetLimit(),
|
||||
date: b.date,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const m = urlPath.match(/^\/flow\/(\d+)\/(\d+)\/(\d+)\.pbf$/);
|
||||
if (!m) {
|
||||
sendJson(404, { error: 'not_found' });
|
||||
return;
|
||||
}
|
||||
const z = Number(m[1]);
|
||||
const x = Number(m[2]);
|
||||
const y = Number(m[3]);
|
||||
if (!isValidTomTomTile(z, x, y)) {
|
||||
sendJson(400, { error: 'invalid_tile' });
|
||||
return;
|
||||
}
|
||||
if (!process.env.TOMTOM_API_KEY) {
|
||||
sendJson(503, { error: 'no_key' });
|
||||
return;
|
||||
}
|
||||
|
||||
const key = `${z}/${x}/${y}`;
|
||||
const now = Date.now();
|
||||
|
||||
let entry = mem.get(key);
|
||||
if (!entry) {
|
||||
entry = await readDiskTile(key);
|
||||
if (entry) memSet(key, entry);
|
||||
}
|
||||
// Fresh cache hit — never counts against the budget.
|
||||
if (entry && now - entry.at < TILE_TTL_MS) {
|
||||
sendTile(entry.buf, 'HIT');
|
||||
return;
|
||||
}
|
||||
|
||||
// Budget governor: over the soft cap, last-good data beats a dead layer.
|
||||
if (isTomTomOverBudget(currentBudget(), dailyBudgetLimit())) {
|
||||
if (entry) {
|
||||
sendTile(entry.buf, 'STALE-BUDGET');
|
||||
} else {
|
||||
sendJson(429, { error: 'budget' });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Stale or missing → refresh, single-flight per tile.
|
||||
if (!inflight.has(key)) {
|
||||
inflight.set(
|
||||
key,
|
||||
fetchUpstream(z, x, y)
|
||||
.then(async (buf) => {
|
||||
const fresh = { at: Date.now(), buf };
|
||||
memSet(key, fresh);
|
||||
await writeDiskTile(key, buf);
|
||||
return fresh;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn(
|
||||
`[tomtom-proxy] ${key} fetch failed (${err?.message || err}) — serving stale if any`,
|
||||
);
|
||||
return null;
|
||||
})
|
||||
.finally(() => inflight.delete(key)),
|
||||
);
|
||||
}
|
||||
const fresh = await inflight.get(key);
|
||||
if (fresh) {
|
||||
sendTile(fresh.buf, 'MISS');
|
||||
} else if (entry) {
|
||||
sendTile(entry.buf, 'STALE-ERROR'); // upstream down — stale beats empty
|
||||
} else {
|
||||
sendJson(502, { error: 'upstream' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[tomtom-proxy] error:', err?.message || err);
|
||||
sendJson(500, { error: 'proxy' });
|
||||
}
|
||||
});
|
||||
},
|
||||
configureServer: installMiddleware,
|
||||
configurePreviewServer: installMiddleware,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user