Port to itty-router

This commit is contained in:
Gabriel Simmer 2024-08-07 11:10:04 +01:00
parent 6aacd7c4d0
commit d121d60b76
Signed by: arch
SSH key fingerprint: SHA256:m3OEcdtrnBpMX+2BDGh/byv3hrCekCLzDYMdvGEKPPQ
3 changed files with 165 additions and 140 deletions

View file

@ -7,6 +7,9 @@
"": { "": {
"name": "worker", "name": "worker",
"version": "0.0.0", "version": "0.0.0",
"dependencies": {
"itty-router": "^5.0.17"
},
"devDependencies": { "devDependencies": {
"@cloudflare/vitest-pool-workers": "^0.4.5", "@cloudflare/vitest-pool-workers": "^0.4.5",
"vitest": "1.5.0", "vitest": "1.5.0",
@ -1574,6 +1577,12 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/itty-router": {
"version": "5.0.17",
"resolved": "https://registry.npmjs.org/itty-router/-/itty-router-5.0.17.tgz",
"integrity": "sha512-ZHnPI0OOyTTLuNp2FdciejYaK4Wl3ZV3O0yEm8njOGggh/k/ek3BL7X2I5YsCOfc5vLhIJgj3Z4pUtLs6k9Ucg==",
"license": "MIT"
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "9.0.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz",

View file

@ -10,7 +10,10 @@
}, },
"devDependencies": { "devDependencies": {
"@cloudflare/vitest-pool-workers": "^0.4.5", "@cloudflare/vitest-pool-workers": "^0.4.5",
"wrangler": "^3.60.3", "vitest": "1.5.0",
"vitest": "1.5.0" "wrangler": "^3.60.3"
},
"dependencies": {
"itty-router": "^5.0.17"
} }
} }

View file

@ -1,24 +1,29 @@
import index from "./index.html"; import index from "./index.html";
import { IttyRouter, json, error, withParams } from 'itty-router'
export default { const router = IttyRouter();
async fetch(request, env, ctx) { const cache = caches.default;
async function withCache(request, env) {
const url = new URL(request.url); const url = new URL(request.url);
const { pathname } = url; const { pathname } = url;
const cacheUrl = new URL(request.url); const cacheUrl = new URL(request.url);
// Construct the cache key from the cache URL // Construct the cache key from the cache URL
const cacheKey = new Request(cacheUrl.toString(), request); const cacheKey = new Request(cacheUrl.toString(), request);
const cache = caches.default;
let response = await cache.match(cacheKey); let response = await cache.match(cacheKey);
if (response) { if (response) {
return response; return response;
} }
request.cacheKey = cacheKey;
}
async function snapshot(request, env, ctx, date = "LATEST") {
const kv = env.KV_STORE; const kv = env.KV_STORE;
const bucket = env.R2_BUCKET; const bucket = env.R2_BUCKET;
const snapshot = async(date = "LATEST") => {
const { value, metadata } = await kv.getWithMetadata(date); const { value, metadata } = await kv.getWithMetadata(date);
if (value == null) { if (value == null) {
return {error: `${date} key not found`}; return {error: `${date} key not found`};
@ -37,11 +42,10 @@ export default {
file: `https://daily-servo-r2.gmem.ca/${value}.png`, file: `https://daily-servo-r2.gmem.ca/${value}.png`,
date: date, date: date,
} }
} }
switch (pathname) { async function renderIndex(request, env, ctx) {
case "/": { let l = await snapshot(request, env, ctx);
let l = await snapshot();
const response = new HTMLRewriter() const response = new HTMLRewriter()
.on("#date", { .on("#date", {
element(element) { element(element) {
@ -62,29 +66,23 @@ export default {
new Response(index, { headers: { "Content-Type": "text/html", new Response(index, { headers: { "Content-Type": "text/html",
"Cache-Control": "s-maxage=3600" } }), "Cache-Control": "s-maxage=3600" } }),
); );
ctx.waitUntil(cache.put(cacheKey, response.clone())); ctx.waitUntil(cache.put(request.cacheKey, response.clone()));
return response return response
} }
case "/latest": {
let l = await latest(); async function latest(request, env) {
if (l.error != undefined) {
return new Response(JSON.stringify(l), {
status: 500,
headers: { "Content-Type": "application/json" }
});
}
return Response.redirect(`${l.file}`, 302);
}
case "/latest.json": {
let l = await snapshot(); let l = await snapshot();
const response = new Response(JSON.stringify(l), { const response = new Response(JSON.stringify(l), {
headers: { "Content-Type": "application/json", headers: { "Content-Type": "application/json",
"Cache-Control": "s-maxage=3600"} "Cache-Control": "s-maxage=3600"}
}); });
ctx.waitUntil(cache.put(cacheKey, response.clone())); ctx.waitUntil(cache.put(request.cacheKey, response.clone()));
return response; return response;
} }
case "/list.json": {
async function snapshotList(request, env, ctx) {
const kv = env.KV_STORE;
let list = await kv.list(); let list = await kv.list();
let filtered = await Promise.all( let filtered = await Promise.all(
list.keys.filter((value) => value.name != "LATEST") list.keys.filter((value) => value.name != "LATEST")
@ -96,11 +94,17 @@ export default {
headers: { "Content-Type": "application/json", headers: { "Content-Type": "application/json",
"Cache-Control": "s-maxage=3600"} "Cache-Control": "s-maxage=3600"}
}); });
ctx.waitUntil(cache.put(cacheKey, response.clone())); ctx.waitUntil(cache.put(request.cacheKey, response.clone()));
return response; return response;
}
async function withAuth(request, env, ctx) {
if (request.headers.get("Authorization") != env.API_TOKEN) {
return new Response("Unauthorized", { status: 403 });
} }
case "/new": { }
if (request.method == "POST" && request.headers.get("Authorization") == env.API_TOKEN) {
async function newSnapshot(request, env, ctx) {
const body = await request.formData(); const body = await request.formData();
const { const {
date, date,
@ -120,21 +124,30 @@ export default {
// Keep for 1 year. // Keep for 1 year.
await kv.put(`${date}`, hash, { expirationTtl: 31_536_000 }); await kv.put(`${date}`, hash, { expirationTtl: 31_536_000 });
return new Response("Uploaded", { status: 201 }); return new Response("Uploaded", { status: 201});
} else { }
return new Response("Unauthorized", { status: 403 });
async function specificSnapshot(request, env, ctx) {
const { pathname } = new URL(request.url);
const response = await snapshot(request, env, ctx, pathname.replace("/", ""))
if (response.error != undefined) {
return new Response(JSON.stringify(response), { status: 404, headers: {"Content-Type": "application/json"} });
} }
} return response
default: }
let snap = await snapshot(pathname.replace("/", ""));
if (snap.error != undefined) { router
return new Response("Not found", { status: 404 }); .get("/", withCache, renderIndex)
} .get("/latest", withCache, latest)
const response = new Response(JSON.stringify(snap), { .get("/latest.json", withCache, snapshot)
headers: { "Content-Type": "application/json", "Cache-Control": "s-maxage=3600" } .get("/list.json", withCache, snapshotList)
}); .post("/new", withAuth, newSnapshot)
ctx.waitUntil(cache.put(cacheKey, response.clone())); .get("*", withCache, specificSnapshot)
return response;
} export default {
}, fetch: (request, ...args) =>
}; router
.fetch(request, ...args)
.then(json)
.catch(error)
}