Files
sub2apipay/src/lib/system-config.ts
2026-03-14 03:45:37 +08:00

130 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { prisma } from '@/lib/db';
// 内存缓存key → { value, expiresAt }
const cache = new Map<string, { value: string; expiresAt: number }>();
const CACHE_TTL_MS = 30_000; // 30 秒
function getCached(key: string): string | undefined {
const entry = cache.get(key);
if (!entry) return undefined;
if (Date.now() > entry.expiresAt) {
cache.delete(key);
return undefined;
}
return entry.value;
}
function setCache(key: string, value: string): void {
cache.set(key, { value, expiresAt: Date.now() + CACHE_TTL_MS });
}
export function invalidateConfigCache(key?: string): void {
if (key) {
cache.delete(key);
} else {
cache.clear();
}
}
export async function getSystemConfig(key: string): Promise<string | undefined> {
const cached = getCached(key);
if (cached !== undefined) return cached;
const row = await prisma.systemConfig.findUnique({ where: { key } });
if (row) {
setCache(key, row.value);
return row.value;
}
// 回退到环境变量
const envVal = process.env[key];
if (envVal !== undefined) {
setCache(key, envVal);
}
return envVal;
}
export async function getSystemConfigs(keys: string[]): Promise<Record<string, string>> {
const result: Record<string, string> = {};
const missing: string[] = [];
for (const key of keys) {
const cached = getCached(key);
if (cached !== undefined) {
result[key] = cached;
} else {
missing.push(key);
}
}
if (missing.length > 0) {
const rows = await prisma.systemConfig.findMany({
where: { key: { in: missing } },
});
const dbMap = new Map(rows.map((r) => [r.key, r.value]));
for (const key of missing) {
const val = dbMap.get(key) ?? process.env[key];
if (val !== undefined) {
result[key] = val;
setCache(key, val);
}
}
}
return result;
}
export async function setSystemConfig(key: string, value: string, group?: string, label?: string): Promise<void> {
await prisma.systemConfig.upsert({
where: { key },
update: { value, ...(group !== undefined && { group }), ...(label !== undefined && { label }) },
create: { key, value, group: group ?? 'general', label },
});
invalidateConfigCache(key);
}
export async function setSystemConfigs(
configs: { key: string; value: string; group?: string; label?: string }[],
): Promise<void> {
await prisma.$transaction(
configs.map((c) =>
prisma.systemConfig.upsert({
where: { key: c.key },
update: {
value: c.value,
...(c.group !== undefined && { group: c.group }),
...(c.label !== undefined && { label: c.label }),
},
create: { key: c.key, value: c.value, group: c.group ?? 'general', label: c.label },
}),
),
);
invalidateConfigCache();
}
export async function getSystemConfigsByGroup(
group: string,
): Promise<{ key: string; value: string; label: string | null }[]> {
return prisma.systemConfig.findMany({
where: { group },
select: { key: true, value: true, label: true },
orderBy: { key: 'asc' },
});
}
export async function getAllSystemConfigs(): Promise<
{ key: string; value: string; group: string; label: string | null }[]
> {
return prisma.systemConfig.findMany({
select: { key: true, value: true, group: true, label: true },
orderBy: [{ group: 'asc' }, { key: 'asc' }],
});
}
export async function deleteSystemConfig(key: string): Promise<void> {
await prisma.systemConfig.delete({ where: { key } }).catch(() => {});
invalidateConfigCache(key);
}