Better enum-based caching for preview images

This commit is contained in:
Jade Ellis 2024-07-24 13:55:49 +01:00
parent 760bb2efeb
commit 9518e41291
No known key found for this signature in database
GPG key ID: 8705A2A3EBF77BD2
4 changed files with 154 additions and 32 deletions

View file

@ -20,7 +20,9 @@
"@sveltejs/adapter-node": "^5.1.1",
"@sveltejs/kit": "^2.5.16",
"@sveltejs/vite-plugin-svelte": "^3.1.1",
"@types/fnv-plus": "^1.3.2",
"@types/node": "^20.14.2",
"@types/polka": "^0.5.7",
"@types/sharedworker": "^0.0.115",
"github-slugger": "^2.0.0",
"glob": "^10.4.1",
@ -76,6 +78,7 @@
"Notes": "file:Notes-1.0.0.tgz",
"acorn": "^8.12.0",
"codemirror": "^6.0.1",
"fnv-plus": "^1.3.1",
"magic-string": "^0.30.10",
"octokit": "^3.2.1",
"satori": "^0.10.14",

View file

@ -1,12 +1,16 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
import type { Middleware } from "polka"
type Req = Parameters<Middleware>[0]
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
interface Platform {
req: Req
}
}
}

View file

@ -1,5 +1,5 @@
import { pages } from '../posts'
import { error } from '@sveltejs/kit'
import { error, type RequestHandler } from '@sveltejs/kit'
import satori from 'satori';
import { Resvg } from '@resvg/resvg-js';
@ -7,13 +7,12 @@ import { SITE_DOMAIN } from '$lib/metadata';
import TTLCache, { } from "@isaacs/ttlcache";
import { format } from "@tusbar/cache-control";
const cache = new TTLCache({ max: 10000, ttl: 1000 * 60 * 60 })
import fnv from "fnv-plus"
// import type { Endpoints } from "@octokit/types";
// let repoRegex = new RegExp("https?://github\.com/(?<repo>[a-zA-Z0-9]+/[a-zA-Z0-9]+)/?")
const fontFile = await fetch('https://og-playground.vercel.app/inter-latin-ext-700-normal.woff');
const fontData: ArrayBuffer = await fontFile.arrayBuffer();
@ -24,9 +23,9 @@ const defaultRatio = 0.5
// const defaultWidth = 800;
const h = (type: any, props: any) => { return { type, props } }
/** @type {import('./$types').RequestHandler} */
export async function GET({ url }) {
type a = RequestHandler;
/** @type {RequestHandler} */
export async function GET({ url, request }) {
const slug = url.searchParams.get('slug')
let dateParts = url.searchParams.get('date')?.split(/[\/-]/)?.map((p: string) => parseInt(p, 10))
if (dateParts && dateParts.length > 3) {
@ -38,30 +37,40 @@ export async function GET({ url }) {
throw error(400, 'Image too big')
}
let image;
if (!cache.has(slug + "/" + dateParts?.join("-") + "/" + width + "/" + ratio)) {
// let start = new Date(dateParts[0] || 1, dateParts[1] || 0, dateParts[2] || 0);
// // @ts-ignore
// let end = new Date(...dateParts);
// console.log(dateParts)
// let start = new Date(dateParts[0] || 1, dateParts[1] || 0, dateParts[2] || 0);
// // @ts-ignore
// let end = new Date(...dateParts);
// console.log(dateParts)
// get post with metadata
const page = pages
.filter((post) => slug === post.slug)
.filter((post) => {
if (dateParts) {
let date = new Date(post.date)
return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth() + 1 == dateParts[1]) &&
(!dateParts[2] || date.getDate() == dateParts[2])
)
} else { return true }
})[0]
// get post with metadata
const page = pages
.filter((post) => slug === post.slug)
.filter((post) => {
if (dateParts) {
let date = new Date(post.date)
return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth() + 1 == dateParts[1]) &&
(!dateParts[2] || date.getDate() == dateParts[2])
)
} else { return true }
})[0]
if (!page) {
throw error(404, 'Post not found')
}
if (!page) {
throw error(404, 'Post not found')
}
let cache_key = fnv.hash(page.canonical + "\x00" + page.readingTime.text + "\x00" + width + "\x00" + ratio).str()
let recieved_etag = request.headers.get("if-none-match");
if (recieved_etag == cache_key) {
console.log("304")
return new Response(null, { status: 304 })
}
if (!cache.has(cache_key)) {
let template = h("div", {
style: {
display: 'flex',
@ -125,12 +134,11 @@ export async function GET({ url }) {
});
image = resvg.render().asPng();
cache.set(slug + "/" + dateParts?.join("-") + "/" + width, image)
;
cache.set(cache_key, image);
} else {
image = cache.get(slug + "/" + dateParts?.join("-") + "/" + width) as Buffer
image = cache.get(cache_key) as Buffer
}
return new Response(image, {
headers: {
'Content-Type': 'image/png',
@ -139,6 +147,7 @@ export async function GET({ url }) {
// immutable: true
maxAge: 60 * 60 * 24
}),
'ETag': cache_key,
'Cross-Origin-Resource-Policy': 'cross-origin'
}
});

106
pnpm-lock.yaml generated
View file

@ -89,6 +89,9 @@ importers:
codemirror:
specifier: ^6.0.1
version: 6.0.1(@lezer/common@1.2.1)
fnv-plus:
specifier: ^1.3.1
version: 1.3.1
magic-string:
specifier: ^0.30.10
version: 0.30.10
@ -147,9 +150,15 @@ importers:
'@sveltejs/vite-plugin-svelte':
specifier: ^3.1.1
version: 3.1.1(svelte@4.2.18)(vite@5.3.1(@types/node@20.14.2)(terser@5.31.1))
'@types/fnv-plus':
specifier: ^1.3.2
version: 1.3.2
'@types/node':
specifier: ^20.14.2
version: 20.14.2
'@types/polka':
specifier: ^0.5.7
version: 0.5.7
'@types/sharedworker':
specifier: ^0.0.115
version: 0.0.115
@ -1097,9 +1106,15 @@ packages:
'@types/aws-lambda@8.10.138':
resolution: {integrity: sha512-71EHMl70TPWIAsFuHd85NHq6S6T2OOjiisPTrH7RgcjzpJpPh4RQJv7PvVvIxc6PIp8CLV7F9B+TdjcAES5vcA==}
'@types/body-parser@1.19.5':
resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
'@types/btoa-lite@1.0.2':
resolution: {integrity: sha512-ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg==}
'@types/connect@3.4.38':
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
'@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
@ -1109,12 +1124,24 @@ packages:
'@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
'@types/express-serve-static-core@4.19.5':
resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==}
'@types/express@4.17.21':
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
'@types/fnv-plus@1.3.2':
resolution: {integrity: sha512-Bgr5yn2dph2q8HZKDS002Pob6vaRTRfhqN9E+TOhjKsJvnfZXULPR3ihH8dL5ZjgxbNhqhTn9hijpbAMPtKZzw==}
'@types/hast@2.3.10':
resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==}
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
'@types/http-errors@2.0.4':
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@ -1124,21 +1151,42 @@ packages:
'@types/mdast@4.0.4':
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
'@types/mime@1.3.5':
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
'@types/ms@0.7.34':
resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==}
'@types/node@20.14.2':
resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==}
'@types/polka@0.5.7':
resolution: {integrity: sha512-TH8CDXM8zoskPCNmWabtK7ziGv9Q21s4hMZLVYK5HFEfqmGXBqq/Wgi7jNELWXftZK/1J/9CezYa06x1RKeQ+g==}
'@types/pug@2.0.10':
resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==}
'@types/qs@6.9.15':
resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==}
'@types/range-parser@1.2.7':
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
'@types/send@0.17.4':
resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
'@types/serve-static@1.15.7':
resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
'@types/sharedworker@0.0.115':
resolution: {integrity: sha512-istxrCv9mbZQt7kXMVMsc4U+dbxG5y+ae5N+9f6pM9VOJmclF7FBWtTog9SMT16s1pZUTjga7ewaMVgqhDpTOg==}
'@types/trouter@3.1.4':
resolution: {integrity: sha512-4YIL/2AvvZqKBWenjvEpxpblT2KGO6793ipr5QS7/6DpQ3O3SwZGgNGWezxf3pzeYZc24a2pJIrR/+Jxh/wYNQ==}
'@types/unist@2.0.10':
resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
@ -1574,6 +1622,9 @@ packages:
resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==}
engines: {node: '>=4.0.0'}
fnv-plus@1.3.1:
resolution: {integrity: sha512-Gz1EvfOneuFfk4yG458dJ3TLJ7gV19q3OM/vVvvHf7eT02Hm1DleB4edsia6ahbKgAYxO9gvyQ1ioWZR+a00Yw==}
foreground-child@3.2.1:
resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==}
engines: {node: '>=14'}
@ -3526,8 +3577,17 @@ snapshots:
'@types/aws-lambda@8.10.138': {}
'@types/body-parser@1.19.5':
dependencies:
'@types/connect': 3.4.38
'@types/node': 20.14.2
'@types/btoa-lite@1.0.2': {}
'@types/connect@3.4.38':
dependencies:
'@types/node': 20.14.2
'@types/cookie@0.6.0': {}
'@types/debug@4.1.12':
@ -3536,6 +3596,22 @@ snapshots:
'@types/estree@1.0.5': {}
'@types/express-serve-static-core@4.19.5':
dependencies:
'@types/node': 20.14.2
'@types/qs': 6.9.15
'@types/range-parser': 1.2.7
'@types/send': 0.17.4
'@types/express@4.17.21':
dependencies:
'@types/body-parser': 1.19.5
'@types/express-serve-static-core': 4.19.5
'@types/qs': 6.9.15
'@types/serve-static': 1.15.7
'@types/fnv-plus@1.3.2': {}
'@types/hast@2.3.10':
dependencies:
'@types/unist': 2.0.10
@ -3544,6 +3620,8 @@ snapshots:
dependencies:
'@types/unist': 3.0.2
'@types/http-errors@2.0.4': {}
'@types/json-schema@7.0.15': {}
'@types/jsonwebtoken@9.0.6':
@ -3554,18 +3632,44 @@ snapshots:
dependencies:
'@types/unist': 3.0.2
'@types/mime@1.3.5': {}
'@types/ms@0.7.34': {}
'@types/node@20.14.2':
dependencies:
undici-types: 5.26.5
'@types/polka@0.5.7':
dependencies:
'@types/express': 4.17.21
'@types/express-serve-static-core': 4.19.5
'@types/node': 20.14.2
'@types/trouter': 3.1.4
'@types/pug@2.0.10': {}
'@types/qs@6.9.15': {}
'@types/range-parser@1.2.7': {}
'@types/resolve@1.20.2': {}
'@types/send@0.17.4':
dependencies:
'@types/mime': 1.3.5
'@types/node': 20.14.2
'@types/serve-static@1.15.7':
dependencies:
'@types/http-errors': 2.0.4
'@types/node': 20.14.2
'@types/send': 0.17.4
'@types/sharedworker@0.0.115': {}
'@types/trouter@3.1.4': {}
'@types/unist@2.0.10': {}
'@types/unist@3.0.2': {}
@ -3990,6 +4094,8 @@ snapshots:
dependencies:
array-back: 3.1.0
fnv-plus@1.3.1: {}
foreground-child@3.2.1:
dependencies:
cross-spawn: 7.0.3