diff --git a/.gitignore b/.gitignore index e42e641e..ae22cc79 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ **/__sapper__ **/.rpt2_cache **/build +/web/data diff --git a/web/package-lock.json b/web/package-lock.json index 80c346c8..2478300e 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1659,6 +1659,11 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "atomically": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-1.7.0.tgz", + "integrity": "sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==" + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", diff --git a/web/package.json b/web/package.json index f57085ad..78dfb962 100644 --- a/web/package.json +++ b/web/package.json @@ -42,7 +42,8 @@ "elementtree": "^0.1.7", "express": "^4.17.1", "node-fetch": "^2.6.1", - "sirv": "^1.0.0" + "sirv": "^1.0.0", + "atomically": "1.7.0" }, "browserslist": [ "last 3 chrome versions", diff --git a/web/src/routes/data/currency.json.ts b/web/src/currency.ts similarity index 87% rename from web/src/routes/data/currency.json.ts rename to web/src/currency.ts index 9cce31e5..4d4d0a3e 100644 --- a/web/src/routes/data/currency.json.ts +++ b/web/src/currency.ts @@ -1,7 +1,8 @@ -import cached from "./_cached"; import { Def } from "util/defs"; import fetch from "node-fetch"; import { parse } from "elementtree"; +import { writeFile } from "atomically"; +import { mkdir } from "fs/promises"; async function btc() { interface Format { @@ -104,10 +105,17 @@ async function ecb() { return defs; } -export const get = cached(3600 * 1000, async () => { - const [btcDefs, ecbDefs] = await Promise.all([btc(), ecb()]); +const DATA_DIR = process.env.DATA_DIR || "data"; +export const currencyPath = `${DATA_DIR}/currency.json`; +export async function updateCurrency() { + const [btcDefs, ecbDefs] = await Promise.all([btc(), ecb()]); const defs: Def[] = [...btcDefs, ...ecbDefs]; - return defs; -}); + await mkdir(DATA_DIR, { recursive: true }); + + await writeFile(currencyPath, JSON.stringify(defs, undefined, "\t"), { + encoding: "utf8", + }); + console.log("Successfully updated file."); +} diff --git a/web/src/routes/data/_cached.ts b/web/src/routes/data/_cached.ts deleted file mode 100644 index 468d5a42..00000000 --- a/web/src/routes/data/_cached.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Request, Response as ExpressResponse } from "express"; -import createEtag from "etag"; - -interface CachedValue { - status: number; - time: Date; - etag: string; - body: string; -} - -export default function cached( - cacheTimeMs: number, - target: () => Promise -) { - let cache: CachedValue | null = null; - return async (req: Request, res: ExpressResponse) => { - if (!cache || cache.time.getTime() - new Date().getTime() > cacheTimeMs) { - try { - const value = await target(); - const body = JSON.stringify(value); - const time = new Date(); - const etag = createEtag(body); - cache = { status: 200, body, etag, time }; - } catch (err) { - console.log("Error updating cached resource:", err); - const time = new Date(); - const body = JSON.stringify({ - code: err.code, - message: err.toString(), - date: time.toISOString(), - }); - const etag = createEtag(body); - cache = { - status: 503, - body, - etag, - time, - }; - } - } - - res.status(cache.status).set({ - ETag: cache.etag, - "Content-Type": "application/json", - "Last-Modified": cache.time.toUTCString(), - }); - res.send(cache.body); - }; -} diff --git a/web/src/server.js b/web/src/server.js index abd8185c..ff615dbb 100644 --- a/web/src/server.js +++ b/web/src/server.js @@ -4,23 +4,43 @@ import sirv from "sirv"; import express from "express"; import compression from "compression"; import * as sapper from "@sapper/server"; +import { updateCurrency, currencyPath } from "./currency.ts"; +import { existsSync } from "fs"; const { PORT, NODE_ENV } = process.env; const dev = NODE_ENV === "development"; -express() - .use( - compression({ threshold: 0 }), - sirv("static", { dev }), - sapper.middleware() - ) - .listen(PORT, (err) => { - if (err) console.log("error", err); - }); +async function batchJob() { + await updateCurrency(); + process.exit(0); +} + +async function main() { + if (!existsSync(currencyPath)) { + await updateCurrency(); + } + + express() + .use("data", sirv(".", { dev })) + .use( + compression({ threshold: 0 }), + sirv("static", { dev }), + sapper.middleware() + ) + .listen(PORT, (err) => { + if (err) console.log("error", err); + }); -async function loadRink() { - let rink = await wasm(); - Rink.setRink(rink); + async function loadRink() { + let rink = await wasm(); + Rink.setRink(rink); + } + + loadRink(); } -loadRink(); +if (process.argv[2] == "batch-job") { + batchJob(); +} else { + main(); +}