mirror of
https://github.com/jason5ng32/MyIP.git
synced 2026-11-04 08:55:47 +00:00
common/ had become the backend's library: 30 of its 41 modules were imported by nothing in the frontend, so the name no longer said what belonged there. It now holds only what the frontend or the build imports too; backend-only code moved to server/, flat except for datasets/ (the dataset engine and its readers). The *-db/ dataset directories stay in common/: self-hosting docs and Docker volumes mount those paths. frontend/utils/ keeps its app-wide modules at the root and gains ip/ (IP / ASN shaping and validation), report/ (the report pipeline) and features/ (the pure layer of a single feature). Paths only — no logic changes. The Dockerfile copies server/, and the AGENTS.md files say where a new module goes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
43 lines
1.9 KiB
JavaScript
43 lines
1.9 KiB
JavaScript
// Boot-time readiness of the offline datasets (server/datasets/datasets.js) and
|
|
// the primed service-status snapshot. The backend listens before any of them
|
|
// is downloaded; runOfflineBootstrap marks that window, and requireOfflineData
|
|
// answers 503 on a route whose data is still missing inside it. Outside the
|
|
// window a missing dataset is a failed download, served degraded as before.
|
|
// A response assembled from independent parts (the ASN Profile) instead asks
|
|
// isStillLoading per part and leaves just that part out, uncached.
|
|
//
|
|
// Snapshots already on disk are loaded before the listener opens (CAIDA,
|
|
// PeeringDB and IEEE at import, MaxMind in backend-server.js), so a restart
|
|
// never hits the gate — only a first boot or a newly added dataset does.
|
|
|
|
let booting = false;
|
|
|
|
// Run the boot steps in parallel, gating until all settle. Steps log their
|
|
// own failures; one that throws still lets the gate go.
|
|
export const runOfflineBootstrap = async (steps) => {
|
|
booting = true;
|
|
try {
|
|
await Promise.allSettled(steps.map((step) => Promise.resolve().then(step)));
|
|
} finally {
|
|
booting = false;
|
|
}
|
|
};
|
|
|
|
// Whether the boot window is open: some offline data may still be on its way.
|
|
export const isOfflineBootstrapping = () => booting;
|
|
|
|
// Whether any of `checks` is unready inside the boot window — data that is
|
|
// on its way, as opposed to a download that already failed.
|
|
export const isStillLoading = (...checks) => booting && checks.some((isReady) => !isReady());
|
|
|
|
// `checks` are the route's `() => boolean` readiness probes (isMaxMindReady,
|
|
// isAsRelLoaded, …). 503 is never edge-cached (cacheable only stamps < 400),
|
|
// so nothing degraded is pinned.
|
|
export const requireOfflineData = (checks) => (req, res, next) => {
|
|
if (isStillLoading(...checks)) {
|
|
res.setHeader('Retry-After', '30');
|
|
return res.status(503).json({ error: 'Offline data is loading' });
|
|
}
|
|
next();
|
|
};
|