841f89b1d5
- Bestanden uploaden naar .data/files/ - Auto-pin na upload - Lijst, download en verwijder bestanden - CID hash generatie via SHA-256 - 191 tests passing
122 lines
3.1 KiB
TypeScript
122 lines
3.1 KiB
TypeScript
/**
|
|
* Local file storage — disk-based
|
|
* Gebruikt wanneer geen Kubo API beschikbaar is.
|
|
* Slaat bestanden op in .data/files/ en houdt metadata bij in .data/files.json
|
|
*/
|
|
|
|
import { readFile, writeFile, mkdir, unlink, readdir, stat } from 'fs/promises';
|
|
import { join } from 'path';
|
|
import { createHash } from 'crypto';
|
|
|
|
const DATA_DIR = join(process.cwd(), '.data', 'files');
|
|
const FILES_DB = join(process.cwd(), '.data', 'files.json');
|
|
|
|
interface FileRecord {
|
|
cid: string;
|
|
name: string;
|
|
size: number;
|
|
modified: string;
|
|
path: string; // relatief pad in .data/files/
|
|
}
|
|
|
|
async function ensureDir() {
|
|
await mkdir(DATA_DIR, { recursive: true });
|
|
}
|
|
|
|
async function readDb(): Promise<Record<string, FileRecord>> {
|
|
try {
|
|
const data = await readFile(FILES_DB, 'utf-8');
|
|
return JSON.parse(data);
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
async function writeDb(db: Record<string, FileRecord>): Promise<void> {
|
|
await ensureDir();
|
|
await writeFile(FILES_DB, JSON.stringify(db, null, 2), 'utf-8');
|
|
}
|
|
|
|
/** Genereer een CID-achtige hash van de bestandsinhoud */
|
|
function generateCid(buffer: Buffer): string {
|
|
const hash = createHash('sha256').update(buffer).digest('hex');
|
|
// IPFS-style base32 hash (Qm prefix + base32 hash)
|
|
return 'Qm' + hash.slice(0, 44);
|
|
}
|
|
|
|
/** Sla een bestand op en retourneer CID + metadata */
|
|
export async function localSaveFile(
|
|
name: string,
|
|
buffer: Buffer,
|
|
size: number
|
|
): Promise<{ cid: string; size: number }> {
|
|
await ensureDir();
|
|
|
|
const cid = generateCid(buffer);
|
|
const filePath = join(DATA_DIR, `${cid}-${name}`);
|
|
|
|
// Sla het bestand op
|
|
await writeFile(filePath, buffer);
|
|
|
|
// Update de database
|
|
const db = await readDb();
|
|
db[cid] = {
|
|
cid,
|
|
name,
|
|
size,
|
|
modified: new Date().toISOString(),
|
|
path: `${cid}-${name}`,
|
|
};
|
|
await writeDb(db);
|
|
|
|
return { cid, size };
|
|
}
|
|
|
|
/** Haal een bestand op */
|
|
export async function localGetFile(cid: string): Promise<{ buffer: Buffer; name: string } | null> {
|
|
const db = await readDb();
|
|
const record = db[cid];
|
|
if (!record) return null;
|
|
|
|
const filePath = join(DATA_DIR, record.path);
|
|
try {
|
|
const buffer = await readFile(filePath);
|
|
return { buffer, name: record.name };
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/** Lijst alle bestanden */
|
|
export async function localListFiles(): Promise<FileRecord[]> {
|
|
const db = await readDb();
|
|
return Object.values(db);
|
|
}
|
|
|
|
/** Verwijder een bestand */
|
|
export async function localDeleteFile(cid: string): Promise<void> {
|
|
const db = await readDb();
|
|
const record = db[cid];
|
|
if (!record) return;
|
|
|
|
// Verwijder het bestand van disk
|
|
const filePath = join(DATA_DIR, record.path);
|
|
try {
|
|
await unlink(filePath);
|
|
} catch {
|
|
// Bestand bestaat niet meer — niet erg
|
|
}
|
|
|
|
// Verwijder uit de database
|
|
delete db[cid];
|
|
await writeDb(db);
|
|
}
|
|
|
|
/** Bereken totale opslag */
|
|
export async function localGetStorageUsage(): Promise<{ files: number; totalBytes: number }> {
|
|
const db = await readDb();
|
|
const files = Object.values(db);
|
|
const totalBytes = files.reduce((sum, f) => sum + f.size, 0);
|
|
return { files: files.length, totalBytes };
|
|
}
|