the best ios gas tracking app
at main 65 lines 2.4 kB view raw
1import { serve } from "bun"; 2import { getDb, getStaleCells, markCellFetched, upsertStations } from "./db.ts"; 3import { handleEIAAverages, refreshEIAAverages } from "./handlers/eia.ts"; 4import { handleHealth } from "./handlers/health.ts"; 5import { handleRegisterKey } from "./handlers/keys.ts"; 6import { logged } from "./logger.ts"; 7import { handleBbox, handleNearby, NEARBY_TTL_MS } from "./handlers/stations.ts"; 8import { handlePrefetchRoute } from "./handlers/prefetch.ts"; 9import { fetchStationsByLocation } from "./gasbuddy.ts"; 10import { cellCenter } from "./geo.ts"; 11 12// Initialize DB on startup 13getDb(); 14 15// Kick off EIA refresh in background (won't block startup) 16refreshEIAAverages(); 17 18// Proactively re-fetch stale cells that were requested in the last 24 hours. 19// Runs every 5 minutes; serializes GasBuddy calls with a 500ms delay. 20async function proactiveRefresh() { 21 const stale = getStaleCells(NEARBY_TTL_MS, 24 * 60 * 60 * 1000); 22 if (stale.length === 0) return; 23 console.log(`[refresh] ${stale.length} stale cells to refresh`); 24 for (const cellKey of stale) { 25 const { lat, lng } = cellCenter(cellKey); 26 try { 27 const stations = await fetchStationsByLocation(lat, lng); 28 upsertStations(stations); 29 } catch (e) { 30 console.error(`[refresh] GasBuddy fetch failed for ${cellKey}:`, e); 31 } 32 markCellFetched(cellKey); // always update timestamp to enforce backoff 33 await new Promise((r) => setTimeout(r, 500)); 34 } 35} 36 37setInterval(proactiveRefresh, 30 * 60 * 1000); // every 30 minutes 38 39const server = serve({ 40 port: process.env.PORT ? parseInt(process.env.PORT, 10) : 7878, 41 42 routes: { 43 "/health": { GET: logged(handleHealth) }, 44 "/keys/register": { POST: logged(handleRegisterKey) }, 45 "/stations/nearby": { GET: logged(handleNearby) }, 46 "/stations/bbox": { GET: logged(handleBbox) }, 47 "/prefetch/route": { POST: logged(handlePrefetchRoute) }, 48 "/eia/averages": { GET: logged(handleEIAAverages) }, 49 }, 50 51 fetch(req) { 52 const url = new URL(req.url); 53 console.log(`${req.method} ${url.pathname} → 404`); 54 return new Response("Not found", { status: 404 }); 55 }, 56}); 57 58console.log(`overpass listening on ${server.hostname}:${server.port}`); 59 60process.on("SIGINT", () => process.exit(0)); 61process.on("SIGTERM", () => process.exit(0)); 62 63process.on("unhandledRejection", (reason) => { 64 console.error("Unhandled rejection:", reason); 65});