import path from 'path'; import fs from 'fs/promises'; import { untarball } from './tarball'; import { lake, backup } from '@iridiumcms/config/server'; import { medias } from '@iridiumcms/db'; import { fromId } from '@iridiumcms/backup/utils'; import { TEMP_DIR } from '@iridiumcms/constants'; import { tables, restoreTable, } from './table-management'; // eslint-disable-next-line require-await export const generator = async function(entry: string) { const { id, isDatabase, isDataLake, } = fromId(entry); const tbPath = path.resolve(TEMP_DIR, entry); const destPath = path.resolve(TEMP_DIR, id); return { async*run() { // remove any existing directory to free up space for the tarball const stat = await fs.stat(destPath).catch(() => null); if (stat?.isDirectory()) { await fs.rm(destPath, { recursive: true }); } await fs.mkdir(destPath, { recursive: true }); yield `retrieving backup`; await Bun.write( path.resolve(TEMP_DIR, entry), await backup.get(entry), ); yield `backup retrieved`; yield `decompressing`; await untarball(destPath, tbPath); yield `decompressing complete`; if (isDatabase) { yield `database: starting restore`; const dbDest = path.resolve(destPath, 'database'); yield `database: ${tables.length} tables`; for (let i = 0; i < tables.length; i++) { const [filename, table] = tables[i]; const jsonPath = path.resolve(dbDest, filename); const ab = await Bun.file(jsonPath).arrayBuffer(); await restoreTable(table, ab); yield `database: ${i + 1}/${tables.length} tables restored`; } yield `database: restore complete`; } if (isDataLake) { yield `data-lake: starting restore`; const dlDest = path.resolve(destPath, 'data-lake'); await fs.mkdir(dlDest, { recursive: true }); const records = await medias.find.files(); yield `data-lake: ${records.length} files`; for (let i = 0; i < records.length; i++) { const { id, mime: type } = records[i] as { id: string; mime: string }; try { const file = await Bun.file(path.resolve(dlDest, id)).arrayBuffer(); await lake.set({ id, file, type, }); } catch (err) { console.error(err); } yield `data-lake: ${i + 1}/${records.length} files restored`; } yield `data-lake: restore complete`; } yield `cleaning up`; await fs.rm(path.resolve(TEMP_DIR, entry), { recursive: true }); await fs.rm(path.resolve(TEMP_DIR, id), { recursive: true }); yield `cleanup complete`; yield `restore complete`; }, }; };