import * as plugins from './smartarchive.plugins.js'; import * as paths from './smartarchive.paths.js'; export class SmartArchive { constructor() {} /** * extracts an archive from a given url */ public async extractArchiveFromUrlToFs(urlArg: string, targetDir: string) { const parsedPath = plugins.path.parse(urlArg); const uniqueFileName = plugins.smartunique.uni() + parsedPath.ext; plugins.smartfile.fs.ensureDir(paths.nogitDir); // TODO: totally remove caching needs const downloadPath = plugins.path.join(paths.nogitDir, uniqueFileName); const downloadedArchive = (await plugins.smartrequest.getBinary(urlArg)).body; await plugins.smartfile.memory.toFs(downloadedArchive, downloadPath); await this.extractArchiveFromFilePathToFs(downloadPath, targetDir); await plugins.smartfile.fs.remove(downloadPath); } /** * extracts an archive from a given filePath on disk * @param filePathArg * @param targetDirArg */ public async extractArchiveFromFilePathToFs(filePathArg: string, targetDirArg: string) { console.log(`extracting ${filePathArg}`); const done = plugins.smartpromise.defer(); filePathArg = plugins.smartpath.transform.makeAbsolute(filePathArg); targetDirArg = plugins.smartpath.transform.makeAbsolute(targetDirArg); const readableStream = plugins.smartfile.fsStream.createReadStream(filePathArg); const extractPipeStop = plugins.tarStream.extract(); extractPipeStop.on('entry', async (header, stream, next) => { const targetFilePath = plugins.path.join(targetDirArg, header.name); const parsedPath = plugins.path.parse(targetFilePath); await plugins.smartfile.fs.ensureDir(parsedPath.dir); const writeStream = plugins.smartfile.fsStream.createWriteStream(targetFilePath); stream.pipe(writeStream); stream.on('end', () => { console.log(`extracted ${header.name}`); next(); }); stream.resume(); }); extractPipeStop.on('finish', () => { console.log(`Sucessfully extracted ${filePathArg}!`); done.resolve(); }); // lets run the stream readableStream.pipe(plugins.gunzipMaybe()).pipe(extractPipeStop); await done.promise; } /** * extracts to Observable * where the Observable is emitting smartfiles */ public async extractArchiveFromBufferToObservable( bufferArg: Buffer ): Promise> { const { intake, replaySubject } = this.extractArchiveWithIntakeAndReplaySubject(); intake.pushData(bufferArg); intake.signalEnd(); return replaySubject; } extractArchiveWithIntakeAndReplaySubject() { const intake = new plugins.smartstream.StreamIntake(); const replaySubject = new plugins.smartrx.rxjs.ReplaySubject(); const readableStream = intake.getReadableStream(); const extractPipeStop = plugins.tarStream.extract(); extractPipeStop.on('entry', (header, stream, next) => { let fileBuffer: Buffer; stream.on('data', (chunkArg) => { if (!fileBuffer) { fileBuffer = chunkArg; } else { fileBuffer = Buffer.concat([fileBuffer, chunkArg]); } }); stream.on('end', () => { replaySubject.next( new plugins.smartfile.Smartfile({ base: null, // no working directory for this one contentBuffer: fileBuffer, path: `${header.name}`, }) ); next(); }); stream.resume(); }); extractPipeStop.on('finish', () => { replaySubject.complete(); }); // lets run the stream readableStream.pipe(plugins.gunzipMaybe()).pipe(extractPipeStop); return { intake, replaySubject, }; } /** * extracts to Observable */ public async extractArchiveFromUrlToObservable( urlArg: string ): Promise> { const response = await plugins.smartrequest.getBinary(urlArg); const replaySubject = this.extractArchiveFromBufferToObservable(response.body); return replaySubject; } // TODO public async extractArchiveFromUrlToStream() {} // TODO public async extractArchiveFromFilePathToStream() {} // TODO public async extractArchiveFromStreamToStream() {} // TODO public async packFromStreamToStream() {} // TODO public async packFromDirPathToStream() {} // TODO public async packFromDirPathToFs() {} }