cache.ts

1.6 KB · raw

1import type { Database } from "bun:sqlite";2import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";3import { join } from "node:path";4import { filesAt, objectBytes } from "../mirror/queries.ts";5import { buildTarball } from "./tar.ts";67/**8 * A save's tarball from `<tarballDir>/<repo>/<id>.tar.gz`, built there on first request. Built and9 * written in one synchronous run, so a strip landing mid-build can't leave a stale file behind.10 */11export function cachedTarball(12	tarballDir: string,13	db: Database,14	repo: string,15	saveId: string,16): Uint8Array<ArrayBuffer> {17	const path = join(tarballDir, repo, `${saveId}.tar.gz`);18	try {19		return readFileSync(path);20	} catch (error) {21		if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;22	}23	const files = filesAt(db, saveId).map((file) => {24		const bytes = objectBytes(db, file.hash);25		if (!bytes) throw new Error(`${repo}: object ${file.hash} is missing from the mirror`);26		return { path: file.path, executable: file.executable, bytes };27	});28	const tarball = buildTarball(`${repo}-${saveId.slice(0, 8)}`, files);29	mkdirSync(join(tarballDir, repo), { recursive: true });30	writeFileSync(`${path}.tmp`, tarball);31	renameSync(`${path}.tmp`, path);32	return tarball;33}3435/** Drops cached tarballs a strip event reaches: one save's, or every one of the repo's for a whole-history strip. */36export function dropTarballs(tarballDir: string, repo: string, saveId: string): void {37	const target =38		saveId === "" ? join(tarballDir, repo) : join(tarballDir, repo, `${saveId}.tar.gz`);39	rmSync(target, { recursive: true, force: true });40}