feat: card-level cache

This commit is contained in:
2026-03-13 17:56:48 +07:00 Unverified
parent 4b9a67476d
commit e7c488d41d
2 changed files with 19 additions and 6 deletions
-1
View File
@@ -6,7 +6,6 @@ declare global {
var forked: boolean;
}
if (cluster.isPrimary) {
if (!globalThis.forked) {
for (let i = 0; i < 2; i++) cluster.fork();
+19 -5
View File
@@ -1,5 +1,5 @@
import { ImageResponse } from "@takumi-rs/image-response";
import { file } from "bun";
import { file, hash } from "bun";
import { NotFoundError, status, t } from "elysia";
import {
fetchEnka,
@@ -7,6 +7,7 @@ import {
InvalidFormatError,
MaintenanceError,
RatelimitError,
TTLCache,
} from "enka.ts";
import { twj } from "tw-to-css";
import type { App } from "@";
@@ -19,6 +20,7 @@ import { TalentSvg } from "@/assets/talent";
import { AssetManager, getEnkaAvatarStore } from "@/lib/assets";
const assets = new AssetManager();
const cache = new TTLCache();
const font = file(fontFile);
const shade = file(shadeSvg);
@@ -41,7 +43,9 @@ export function card(app: App) {
// const data = mockData;
const [avatarStore, data] = await Promise.all([
getEnkaAvatarStore().finally(() =>
console.log(`${Date.now() - start}ms - Avatar store loaded`),
console.log(
`\n${Date.now() - start}ms - Avatar store loaded`,
),
),
fetchEnka(uid, false).finally(() =>
console.log(`${Date.now() - start}ms - Enka data loaded`),
@@ -57,9 +61,14 @@ export function card(app: App) {
const avatar = avatarStore[char.avatar.avatarId];
if (!avatar)
return status(
500,
400,
"Unsupported character, avatar store doesn't have this character",
);
const cacheKey = hash(JSON.stringify(data)).toString(36);
const cached = cache.get<ImageResponse>(cacheKey);
if (cached) return cached;
const resources = await Promise.all([
...[...avatar.Consts, ...Object.values(avatar.Skills)].map(
async (path) => ({
@@ -80,7 +89,7 @@ export function card(app: App) {
data,
})),
assets
.fnCache("bg", () =>
.fnCache(`bg-${avatar.Element}`, () =>
generateBackground({
element: avatar.Element,
width: 1218,
@@ -101,7 +110,7 @@ export function card(app: App) {
char.propMap?.[1002].val ?? 1
];
return new ImageResponse(
const res = new ImageResponse(
<div tw="relative text-[32.25px] text-white rounded-xl overflow-hidden">
<div tw="aspect-[1218/508] h-full">
<img
@@ -259,6 +268,11 @@ export function card(app: App) {
],
},
);
queueMicrotask(() => {
cache.set(cacheKey, res, 1000 * 60 * 60 * 24); // cache for 24 hour
});
return res.clone();
} catch (err) {
if (err instanceof InvalidFormatError)
return status(400, "Invalid UID format");