66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
import { Database } from 'bun:sqlite';
|
|
import { createHash } from 'crypto';
|
|
import path from 'path';
|
|
import fs from 'fs/promises';
|
|
|
|
type CacheRow = {
|
|
path_key: string,
|
|
fpath: string,
|
|
etag: string,
|
|
size: number,
|
|
mime: string | null,
|
|
cache_path: string,
|
|
updated_at: number
|
|
};
|
|
|
|
export const CACHE_DIR = "/tmp",
|
|
db = new Database(path.resolve(`${CACHE_DIR}/index.sqlite`));
|
|
|
|
db.run(`
|
|
create table if not exists file_cache (
|
|
path_key text primary key,
|
|
fpath text not null,
|
|
etag text not null,
|
|
size integer not null,
|
|
mime text,
|
|
cache_path text not null,
|
|
updated_at integer not null
|
|
);
|
|
`);
|
|
|
|
const qGet = db.query<CacheRow, string>('select * from file_cache where path_key = ?;');
|
|
|
|
const qUpsert = db.query(`
|
|
insert into file_cache (path_key, fpath, etag, size, mime, cache_path, updated_at)
|
|
values (?1, ?2, ?3, ?4, ?5, ?6, ?7)
|
|
on conflict(path_key) do update set
|
|
etag=excluded.etag, size=excluded.size, mime=excluded.mime,
|
|
cache_path=excluded.cache_path, updated_at=excluded.updated_at;
|
|
`);
|
|
|
|
export const base64url = (buf: Buffer): string =>
|
|
buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); // no padding
|
|
|
|
export const pathKey = (addr: string, fpath: string): string => {
|
|
// normalize to avoid duplicate keys for equivalent paths
|
|
const canonical = new URL(fpath, addr).toString(),
|
|
digest = createHash('sha256').update(canonical).digest();
|
|
|
|
return base64url(digest);
|
|
};
|
|
|
|
export const fanoutPath = (key: string): string =>
|
|
path.join(`${CACHE_DIR}/files`, key.slice(0, 2), key.slice(2, 4), key);
|
|
|
|
export async function ensureDir(p: string): Promise<void> {
|
|
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
}
|
|
|
|
export function getRow(key: string): CacheRow | undefined {
|
|
return qGet.get(key) as unknown as CacheRow | undefined;
|
|
}
|
|
|
|
export function upsertRow(row: CacheRow): void {
|
|
qUpsert.run(row.path_key, row.fpath, row.etag, row.size, row.mime, row.cache_path, row.updated_at);
|
|
}
|