mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 11:24:00 +00:00
refactor: separate Overpass and installation services
This commit is contained in:
1 parent
781613fbb8
commit
213edd80ce
14 files changed
+1455
-841
No files matched your search
@@ -0,0 +1,134 @@
|
||||
import { MILITARY_INSTALLATION_CACHE_MS, MILITARY_INSTALLATION_ELEMENT_CAP, MILITARY_INSTALLATION_DISK_TTL_MS, MILITARY_INSTALLATION_DISK_DIR, MILITARY_INSTALLATION_MAX_CACHE } from './constants.js';
|
||||
import path from 'node:path';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { promises as fsp } from 'node:fs';
|
||||
|
||||
const _militaryInstallationCache = new Map();
|
||||
|
||||
/**
|
||||
* Resolve the READ tiers for one installation request, in order: fresh memory,
|
||||
* then disk. Returns UPSTREAM when neither can answer.
|
||||
*
|
||||
* Disk is skipped while a request for this key is already in flight — the
|
||||
* caller joins that instead of paying a read. Exported so the tier ORDER is
|
||||
* testable against a real temp directory without a Vite server, mirroring
|
||||
* resolveOverpassPreflight.
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {string} options.cacheKey
|
||||
* @param {Map<string, {payload: object, cachedAt: number}>} options.memoryCache
|
||||
* @param {Map<string, Promise>} options.inFlight
|
||||
* @param {() => Promise<?{payload: object, cachedAt: number}>} options.readDisk
|
||||
* @param {number} [options.now]
|
||||
* @param {number} [options.cacheMs]
|
||||
* @returns {Promise<{source: 'HIT'|'DISK'|'UPSTREAM', entry: ?object}>}
|
||||
*/
|
||||
async function resolveMilitaryInstallationTier({
|
||||
cacheKey,
|
||||
memoryCache,
|
||||
inFlight,
|
||||
readDisk,
|
||||
now = Date.now(),
|
||||
cacheMs = MILITARY_INSTALLATION_CACHE_MS,
|
||||
}) {
|
||||
const cached = memoryCache.get(cacheKey);
|
||||
if (cached && now - cached.cachedAt <= cacheMs) return { source: 'HIT', entry: cached };
|
||||
if (inFlight.has(cacheKey)) return { source: 'UPSTREAM', entry: null };
|
||||
const disk = await readDisk();
|
||||
return disk ? { source: 'DISK', entry: disk } : { source: 'UPSTREAM', entry: null };
|
||||
}
|
||||
|
||||
/**
|
||||
* Bring a stored installation entry up to the current payload shape.
|
||||
*
|
||||
* Entries written before the saturation guard shipped carry no `saturated`
|
||||
* field, and the disk TTL is 30 DAYS — so without this a cached, truncated
|
||||
* 700-element snapped response would keep skipping the exact-viewport retry for
|
||||
* a month, quietly starving in-view sites. Saturation is DERIVED from the
|
||||
* element count rather than invalidating those entries, so warm caches survive
|
||||
* the upgrade.
|
||||
* @param {?{payload: object, cachedAt: number}} entry
|
||||
* @returns {?{payload: object, cachedAt: number}}
|
||||
*/
|
||||
function migrateMilitaryInstallationEntry(entry) {
|
||||
if (!entry?.payload || typeof entry.payload.saturated === 'boolean') return entry;
|
||||
const elements = Array.isArray(entry.payload.elements) ? entry.payload.elements : [];
|
||||
return {
|
||||
...entry,
|
||||
payload: {
|
||||
...entry.payload,
|
||||
saturated: elements.length >= MILITARY_INSTALLATION_ELEMENT_CAP,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** Whether a stored installation entry is still inside its TTL. */
|
||||
function militaryInstallationDiskFresh(
|
||||
entry,
|
||||
maxAgeMs = MILITARY_INSTALLATION_DISK_TTL_MS,
|
||||
now = Date.now(),
|
||||
) {
|
||||
if (!entry || !Number.isFinite(entry.cachedAt) || !Array.isArray(entry.payload?.elements)) return false;
|
||||
return now - entry.cachedAt <= maxAgeMs;
|
||||
}
|
||||
|
||||
/** Cache key -> stable disk-cache file path. */
|
||||
function militaryInstallationDiskPath(cacheKey, dir = MILITARY_INSTALLATION_DISK_DIR) {
|
||||
return path.join(dir, `${createHash('sha1').update(cacheKey).digest('hex')}.json`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a disk-cached installation entry. maxAgeMs Infinity = any age (the
|
||||
* serve-stale path when Overpass is down).
|
||||
* @returns {Promise<?{payload: object, cachedAt: number}>}
|
||||
*/
|
||||
async function readMilitaryInstallationDisk(
|
||||
cacheKey,
|
||||
maxAgeMs,
|
||||
dir = MILITARY_INSTALLATION_DISK_DIR,
|
||||
) {
|
||||
try {
|
||||
const entry = JSON.parse(await fsp.readFile(militaryInstallationDiskPath(cacheKey, dir), 'utf8'));
|
||||
if (!militaryInstallationDiskFresh(entry, maxAgeMs)) return null;
|
||||
return migrateMilitaryInstallationEntry(entry);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist one installation payload ATOMICALLY: serialize to a temp sibling,
|
||||
* then rename over the target. A crash or a full disk mid-write leaves the
|
||||
* PREVIOUS entry intact — an in-place overwrite would shred the last-good copy
|
||||
* and take serve-stale down with it, exactly when it is needed most.
|
||||
* @returns {Promise<boolean>} Whether the entry landed.
|
||||
*/
|
||||
async function writeMilitaryInstallationDisk(
|
||||
cacheKey,
|
||||
entry,
|
||||
dir = MILITARY_INSTALLATION_DISK_DIR,
|
||||
) {
|
||||
const target = militaryInstallationDiskPath(cacheKey, dir);
|
||||
// Same directory, so the rename is atomic on POSIX rather than a cross-device copy.
|
||||
const temp = `${target}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
||||
try {
|
||||
await fsp.mkdir(dir, { recursive: true });
|
||||
await fsp.writeFile(temp, JSON.stringify(entry));
|
||||
await fsp.rename(temp, target);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.warn('[Installations Proxy] disk cache write failed:', err?.message || err);
|
||||
await fsp.rm(temp, { force: true }).catch(() => {});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function trimMilitaryInstallationCache() {
|
||||
while (_militaryInstallationCache.size > MILITARY_INSTALLATION_MAX_CACHE) {
|
||||
const oldest = _militaryInstallationCache.keys().next().value;
|
||||
if (oldest === undefined) break;
|
||||
_militaryInstallationCache.delete(oldest);
|
||||
}
|
||||
}
|
||||
|
||||
export { _militaryInstallationCache, trimMilitaryInstallationCache, writeMilitaryInstallationDisk, resolveMilitaryInstallationTier, readMilitaryInstallationDisk, migrateMilitaryInstallationEntry, militaryInstallationDiskFresh, militaryInstallationDiskPath };
|
||||
Reference in new issue
Block a user