Port to itty-router
This commit is contained in:
parent
6aacd7c4d0
commit
d121d60b76
9
worker/package-lock.json
generated
9
worker/package-lock.json
generated
|
@ -7,6 +7,9 @@
|
|||
"": {
|
||||
"name": "worker",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"itty-router": "^5.0.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/vitest-pool-workers": "^0.4.5",
|
||||
"vitest": "1.5.0",
|
||||
|
@ -1574,6 +1577,12 @@
|
|||
"dev": true,
|
||||
"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": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz",
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@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"
|
||||
}
|
||||
}
|
|
@ -1,140 +1,153 @@
|
|||
import index from "./index.html";
|
||||
import { IttyRouter, json, error, withParams } from 'itty-router'
|
||||
|
||||
const router = IttyRouter();
|
||||
const cache = caches.default;
|
||||
|
||||
async function withCache(request, env) {
|
||||
const url = new URL(request.url);
|
||||
const { pathname } = url;
|
||||
const cacheUrl = new URL(request.url);
|
||||
|
||||
// Construct the cache key from the cache URL
|
||||
const cacheKey = new Request(cacheUrl.toString(), request);
|
||||
let response = await cache.match(cacheKey);
|
||||
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
request.cacheKey = cacheKey;
|
||||
}
|
||||
|
||||
async function snapshot(request, env, ctx, date = "LATEST") {
|
||||
const kv = env.KV_STORE;
|
||||
const bucket = env.R2_BUCKET;
|
||||
|
||||
const { value, metadata } = await kv.getWithMetadata(date);
|
||||
if (value == null) {
|
||||
return {error: `${date} key not found`};
|
||||
}
|
||||
const object = await bucket.get(`${value}.png`);
|
||||
if (object === null) {
|
||||
return {error: `${date} object not found`};
|
||||
}
|
||||
|
||||
if (metadata != null) {
|
||||
date = metadata.date;
|
||||
}
|
||||
|
||||
return {
|
||||
hash: value,
|
||||
file: `https://daily-servo-r2.gmem.ca/${value}.png`,
|
||||
date: date,
|
||||
}
|
||||
}
|
||||
|
||||
async function renderIndex(request, env, ctx) {
|
||||
let l = await snapshot(request, env, ctx);
|
||||
const response = new HTMLRewriter()
|
||||
.on("#date", {
|
||||
element(element) {
|
||||
element.setInnerContent(l.date);
|
||||
},
|
||||
})
|
||||
.on("#img", {
|
||||
element(element) {
|
||||
element.setAttribute("src", l.file);
|
||||
},
|
||||
})
|
||||
.on("#img-link", {
|
||||
element(element) {
|
||||
element.setAttribute("href", l.file);
|
||||
},
|
||||
})
|
||||
.transform(
|
||||
new Response(index, { headers: { "Content-Type": "text/html",
|
||||
"Cache-Control": "s-maxage=3600" } }),
|
||||
);
|
||||
ctx.waitUntil(cache.put(request.cacheKey, response.clone()));
|
||||
return response
|
||||
}
|
||||
|
||||
async function latest(request, env) {
|
||||
let l = await snapshot();
|
||||
const response = new Response(JSON.stringify(l), {
|
||||
headers: { "Content-Type": "application/json",
|
||||
"Cache-Control": "s-maxage=3600"}
|
||||
});
|
||||
ctx.waitUntil(cache.put(request.cacheKey, response.clone()));
|
||||
return response;
|
||||
}
|
||||
|
||||
async function snapshotList(request, env, ctx) {
|
||||
const kv = env.KV_STORE;
|
||||
|
||||
let list = await kv.list();
|
||||
let filtered = await Promise.all(
|
||||
list.keys.filter((value) => value.name != "LATEST")
|
||||
.map(async (value) => { const v = await kv.get(value.name); return { date: value.name, hash: v } } ));
|
||||
const response = new Response(JSON.stringify({
|
||||
latest: await kv.get("LATEST"),
|
||||
list: filtered,
|
||||
}), {
|
||||
headers: { "Content-Type": "application/json",
|
||||
"Cache-Control": "s-maxage=3600"}
|
||||
});
|
||||
ctx.waitUntil(cache.put(request.cacheKey, response.clone()));
|
||||
return response;
|
||||
}
|
||||
|
||||
async function withAuth(request, env, ctx) {
|
||||
if (request.headers.get("Authorization") != env.API_TOKEN) {
|
||||
return new Response("Unauthorized", { status: 403 });
|
||||
}
|
||||
}
|
||||
|
||||
async function newSnapshot(request, env, ctx) {
|
||||
const body = await request.formData();
|
||||
const {
|
||||
date,
|
||||
hash,
|
||||
file
|
||||
} = Object.fromEntries(body)
|
||||
|
||||
// Don't bother uploading to R2 if the hashes match.
|
||||
let latest = kv.get("LATEST");
|
||||
if (latest != hash) {
|
||||
await bucket.put(`${hash}.png`, file);
|
||||
}
|
||||
|
||||
await kv.put("LATEST", hash, {
|
||||
metadata: { date: date }
|
||||
});
|
||||
// Keep for 1 year.
|
||||
await kv.put(`${date}`, hash, { expirationTtl: 31_536_000 });
|
||||
|
||||
return new Response("Uploaded", { status: 201});
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
router
|
||||
.get("/", withCache, renderIndex)
|
||||
.get("/latest", withCache, latest)
|
||||
.get("/latest.json", withCache, snapshot)
|
||||
.get("/list.json", withCache, snapshotList)
|
||||
.post("/new", withAuth, newSnapshot)
|
||||
.get("*", withCache, specificSnapshot)
|
||||
|
||||
export default {
|
||||
async fetch(request, env, ctx) {
|
||||
const url = new URL(request.url);
|
||||
const { pathname } = url;
|
||||
|
||||
const cacheUrl = new URL(request.url);
|
||||
|
||||
// Construct the cache key from the cache URL
|
||||
const cacheKey = new Request(cacheUrl.toString(), request);
|
||||
const cache = caches.default;
|
||||
let response = await cache.match(cacheKey);
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
const kv = env.KV_STORE;
|
||||
const bucket = env.R2_BUCKET;
|
||||
|
||||
const snapshot = async(date = "LATEST") => {
|
||||
const { value, metadata } = await kv.getWithMetadata(date);
|
||||
if (value == null) {
|
||||
return {error: `${date} key not found`};
|
||||
}
|
||||
const object = await bucket.get(`${value}.png`);
|
||||
if (object === null) {
|
||||
return {error: `${date} object not found`};
|
||||
}
|
||||
|
||||
if (metadata != null) {
|
||||
date = metadata.date;
|
||||
}
|
||||
|
||||
return {
|
||||
hash: value,
|
||||
file: `https://daily-servo-r2.gmem.ca/${value}.png`,
|
||||
date: date,
|
||||
}
|
||||
}
|
||||
|
||||
switch (pathname) {
|
||||
case "/": {
|
||||
let l = await snapshot();
|
||||
const response = new HTMLRewriter()
|
||||
.on("#date", {
|
||||
element(element) {
|
||||
element.setInnerContent(l.date);
|
||||
},
|
||||
})
|
||||
.on("#img", {
|
||||
element(element) {
|
||||
element.setAttribute("src", l.file);
|
||||
},
|
||||
})
|
||||
.on("#img-link", {
|
||||
element(element) {
|
||||
element.setAttribute("href", l.file);
|
||||
},
|
||||
})
|
||||
.transform(
|
||||
new Response(index, { headers: { "Content-Type": "text/html",
|
||||
"Cache-Control": "s-maxage=3600" } }),
|
||||
);
|
||||
ctx.waitUntil(cache.put(cacheKey, response.clone()));
|
||||
return response
|
||||
}
|
||||
case "/latest": {
|
||||
let l = await latest();
|
||||
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();
|
||||
const response = new Response(JSON.stringify(l), {
|
||||
headers: { "Content-Type": "application/json",
|
||||
"Cache-Control": "s-maxage=3600"}
|
||||
});
|
||||
ctx.waitUntil(cache.put(cacheKey, response.clone()));
|
||||
return response;
|
||||
}
|
||||
case "/list.json": {
|
||||
let list = await kv.list();
|
||||
let filtered = await Promise.all(
|
||||
list.keys.filter((value) => value.name != "LATEST")
|
||||
.map(async (value) => { const v = await kv.get(value.name); return { date: value.name, hash: v } } ));
|
||||
const response = new Response(JSON.stringify({
|
||||
latest: await kv.get("LATEST"),
|
||||
list: filtered,
|
||||
}), {
|
||||
headers: { "Content-Type": "application/json",
|
||||
"Cache-Control": "s-maxage=3600"}
|
||||
});
|
||||
ctx.waitUntil(cache.put(cacheKey, response.clone()));
|
||||
return response;
|
||||
}
|
||||
case "/new": {
|
||||
if (request.method == "POST" && request.headers.get("Authorization") == env.API_TOKEN) {
|
||||
const body = await request.formData();
|
||||
const {
|
||||
date,
|
||||
hash,
|
||||
file
|
||||
} = Object.fromEntries(body)
|
||||
|
||||
// Don't bother uploading to R2 if the hashes match.
|
||||
let latest = kv.get("LATEST");
|
||||
if (latest != hash) {
|
||||
await bucket.put(`${hash}.png`, file);
|
||||
}
|
||||
|
||||
await kv.put("LATEST", hash, {
|
||||
metadata: { date: date }
|
||||
});
|
||||
// Keep for 1 year.
|
||||
await kv.put(`${date}`, hash, { expirationTtl: 31_536_000 });
|
||||
|
||||
return new Response("Uploaded", { status: 201 });
|
||||
} else {
|
||||
return new Response("Unauthorized", { status: 403 });
|
||||
}
|
||||
}
|
||||
default:
|
||||
let snap = await snapshot(pathname.replace("/", ""));
|
||||
if (snap.error != undefined) {
|
||||
return new Response("Not found", { status: 404 });
|
||||
}
|
||||
const response = new Response(JSON.stringify(snap), {
|
||||
headers: { "Content-Type": "application/json", "Cache-Control": "s-maxage=3600" }
|
||||
});
|
||||
ctx.waitUntil(cache.put(cacheKey, response.clone()));
|
||||
return response;
|
||||
}
|
||||
},
|
||||
};
|
||||
fetch: (request, ...args) =>
|
||||
router
|
||||
.fetch(request, ...args)
|
||||
.then(json)
|
||||
.catch(error)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue