From bfd291e7d6239798f4c81a2552914ed6e5a00202 Mon Sep 17 00:00:00 2001 From: DecafDev <40307803+decaf-dev@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:14:32 -0600 Subject: [PATCH] Add social image cache (#223) * feat: add social image cache * feat: add cached entry expiration time --- bun.lockb | Bin 191659 -> 191985 bytes package.json | 1 + src/svelte/app/components/grid-card.svelte | 4 +- src/svelte/app/services/social-media-image.ts | 72 +++++++++++++++++- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/bun.lockb b/bun.lockb index a45f0b28ba8e98c9bca94070f818e30019d1431b..5306e1cab3f42b2739131fb97d793bac287678e8 100755 GIT binary patch delta 33490 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 { +const DATABASE_NAME = "vaultexplorer"; +const STORE_NAME = "socialMediaImage"; +const ENTRY_EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 7; //1 week + +interface SocialImageDB extends DBSchema { + socialMediaImage: { + key: string; + value: { + url: string; + socialImageUrl: string; + timestamp: number; + }; + }; +} + +export const clearSocialImageCache = async () => { + Logger.trace({ + fileName: "social-media-image.ts", + functionName: "clearSocialMediaImageCache", + message: "called", + }); + const db = await openDatabase(); + await db.clear(STORE_NAME); +}; + +export const fetchSocialImage = async (url: string) => { Logger.trace({ fileName: "social-media-image.ts", functionName: "fetchSocialMediaImage", @@ -9,6 +35,28 @@ export const fetchSocialMediaImage = async (url: string) => { }); try { + const entry = await getCachedSocialImageEntry(url); + if (entry !== null) { + Logger.trace( + { + fileName: "social-media-image.ts", + functionName: "fetchSocialMediaImage", + message: "found cached entry", + }, + entry + ); + if (Date.now() - entry.timestamp < ENTRY_EXPIRATION_TIME) { + const { socialImageUrl } = entry; + Logger.debug({ + fileName: "social-media-image.ts", + functionName: "fetchSocialMediaImage", + message: + "timestamp is within expiration time. returning cached image url", + }); + return socialImageUrl; + } + } + const response = await requestUrl({ url, method: "GET", @@ -32,6 +80,7 @@ export const fetchSocialMediaImage = async (url: string) => { }, { imageUrl } ); + await putSocialImageUrl(url, imageUrl); } else { Logger.warn( { @@ -51,7 +100,7 @@ export const fetchSocialMediaImage = async (url: string) => { functionName: "fetchSocialMediaImage", message: "failed to fetch", }, - { url, error } + error ); return null; } @@ -63,3 +112,22 @@ const getMetaTagContent = (document: Document, property: string) => { document.querySelector(`meta[name='${property}']`); return tag ? tag.getAttribute("content") : ""; }; + +const putSocialImageUrl = async (url: string, socialImageUrl: string) => { + const db = await openDatabase(); + db.put(STORE_NAME, { url, socialImageUrl, timestamp: Date.now() }); +}; + +const getCachedSocialImageEntry = async (url: string) => { + const db = await openDatabase(); + const cachedEntry = await db.get(STORE_NAME, url); + return cachedEntry ?? null; +}; + +const openDatabase = (): Promise> => { + return openDB(DATABASE_NAME, 1, { + upgrade(db) { + db.createObjectStore(STORE_NAME, { keyPath: "url" }); + }, + }); +};