79 lines
1.8 KiB
TypeScript
79 lines
1.8 KiB
TypeScript
import { mkdir, readdir, rm, stat } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
|
|
const JOB_TTL_MS = 15 * 60 * 1000;
|
|
const JOBS_ROOT = path.join(tmpdir(), "kk-card-jobs");
|
|
const JOB_ID_RE =
|
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
|
|
export function isJobId(id: string): boolean {
|
|
return JOB_ID_RE.test(id);
|
|
}
|
|
|
|
export function jobDir(id: string): string {
|
|
return path.join(JOBS_ROOT, id);
|
|
}
|
|
|
|
export function jobZipPath(id: string): string {
|
|
return path.join(jobDir(id), "ids.zip");
|
|
}
|
|
|
|
export async function sweepExpiredJobs(): Promise<void> {
|
|
let names: string[] = [];
|
|
try {
|
|
names = await readdir(JOBS_ROOT);
|
|
} catch {
|
|
return;
|
|
}
|
|
|
|
const cutoff = Date.now() - JOB_TTL_MS;
|
|
await Promise.all(
|
|
names.map(async (name) => {
|
|
const dir = path.join(JOBS_ROOT, name);
|
|
try {
|
|
const info = await stat(dir);
|
|
if (info.mtimeMs >= cutoff) return;
|
|
await rm(dir, { recursive: true, force: true });
|
|
} catch {
|
|
// ignore missing or locked job folders
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
|
|
export async function createJobDir(): Promise<{
|
|
id: string;
|
|
dir: string;
|
|
pngDir: string;
|
|
imagePath: string;
|
|
zipPath: string;
|
|
}> {
|
|
await sweepExpiredJobs();
|
|
const id = crypto.randomUUID();
|
|
const dir = jobDir(id);
|
|
const pngDir = path.join(dir, "png");
|
|
await mkdir(pngDir, { recursive: true });
|
|
return {
|
|
id,
|
|
dir,
|
|
pngDir,
|
|
imagePath: path.join(dir, "base"),
|
|
zipPath: jobZipPath(id),
|
|
};
|
|
}
|
|
|
|
export async function getJobZip(
|
|
id: string,
|
|
): Promise<{ zipPath: string; size: number } | null> {
|
|
if (!isJobId(id)) return null;
|
|
const zipPath = jobZipPath(id);
|
|
try {
|
|
const info = await stat(zipPath);
|
|
if (!info.isFile() || info.size === 0) return null;
|
|
return { zipPath, size: info.size };
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|