Files
Calbook/lib/settings.ts

110 lines
2.6 KiB
TypeScript

import { prisma } from "@/lib/prisma";
import { DEFAULT_SETTINGS } from "@/lib/constants";
type SettingsCacheEntry = {
value: string;
expiresAt: number;
};
declare global {
// eslint-disable-next-line no-var
var calbookSettingsCache: Map<string, SettingsCacheEntry> | undefined;
}
const settingsCache = global.calbookSettingsCache ?? new Map<string, SettingsCacheEntry>();
if (!global.calbookSettingsCache) {
global.calbookSettingsCache = settingsCache;
}
const SETTINGS_CACHE_TTL_MS = Number(process.env.SETTINGS_CACHE_TTL_MS ?? "30000");
function nowMs() {
return Date.now();
}
function readCachedSetting(key: string): string | null {
const entry = settingsCache.get(key);
if (!entry) return null;
if (entry.expiresAt <= nowMs()) {
settingsCache.delete(key);
return null;
}
return entry.value;
}
function writeCachedSetting(key: string, value: string) {
settingsCache.set(key, {
value,
expiresAt: nowMs() + SETTINGS_CACHE_TTL_MS
});
}
export function clearSettingsCache() {
settingsCache.clear();
}
export async function getSettings(keys?: string[]) {
const map: Record<string, string> = { ...DEFAULT_SETTINGS };
if (keys && keys.length > 0) {
const keySet = Array.from(new Set(keys));
const missing: string[] = [];
for (const key of keySet) {
const cached = readCachedSetting(key);
if (cached === null) {
missing.push(key);
} else {
map[key] = cached;
}
}
if (missing.length > 0) {
const records = await prisma.setting.findMany({
where: { key: { in: missing } }
});
const byKey = new Map(records.map((row) => [row.key, row.value]));
for (const key of missing) {
const value = byKey.get(key) ?? DEFAULT_SETTINGS[key] ?? "";
writeCachedSetting(key, value);
map[key] = value;
}
}
return map;
}
const records = await prisma.setting.findMany();
for (const row of records) {
map[row.key] = row.value;
writeCachedSetting(row.key, row.value);
}
return map;
}
export async function getSetting(key: string): Promise<string> {
const cached = readCachedSetting(key);
if (cached !== null) return cached;
const settings = await getSettings([key]);
return settings[key] ?? DEFAULT_SETTINGS[key] ?? "";
}
export async function setSettings(values: Record<string, string>) {
const entries = Object.entries(values);
await prisma.$transaction(
entries.map(([key, value]) =>
prisma.setting.upsert({
where: { key },
create: { key, value },
update: { value }
})
)
);
for (const [key, value] of entries) {
writeCachedSetting(key, value);
}
}