import { CBFileSystem } from "../node/file-system"; import archiver from 'archiver'; import path from 'path'; import { __logger } from "../logger/internal-logger"; import * as yauzl from 'yauzl'; import fs from 'fs'; import { createWriteStream } from 'fs'; /** * Archive service for managing zip file creation and extraction */ export class ArchiveService { constructor(private fileSystem: CBFileSystem) { } /** * Creates the zip package * @param {string[]} files - Array of files to package * @param {string} appDir - The application directory * @param {string} outputPath - The output path for the package */ createZipPackage(files: string[], appDir: string, outputPath: string): Promise { return new Promise((resolve, reject) => { const output = this.fileSystem.createWriteStream(outputPath); const archive = archiver('zip'); output.on('close', () => { __logger.info(`Archive created: ${archive.pointer()} total bytes`); resolve(); }); output.on('error', (err: Error) => { __logger.error('Error writing to output file:', err); reject(err); }); archive.on('error', (err: Error) => { __logger.error('Error creating archive:', err); reject(err); }); archive.pipe(output); // Add files to the archive files.forEach(file => { const filePath = path.join(appDir, file); if (this.fileSystem.existsSync(filePath)) { archive.file(filePath, { name: file }); __logger.info(` - Added: ${file}`); } }); archive.finalize(); }); } /** * Extract zip file to specified directory using yauzl * @param {string} zipFilePath - Path to the zip file * @param {string} extractDir - Directory to extract contents to */ extractZipFile(zipFilePath: string, extractDir: string): Promise { return new Promise((resolve, reject) => { yauzl.open(zipFilePath, { lazyEntries: true }, (err, zipfile) => { if (err) { __logger.error('Error opening zip file:', err); reject(err); return; } zipfile.readEntry(); zipfile.on('entry', (entry) => { if (/\/$/.test(entry.fileName)) { // Directory entry const dirPath = path.join(extractDir, entry.fileName); fs.mkdirSync(dirPath, { recursive: true }); zipfile.readEntry(); } else { // File entry zipfile.openReadStream(entry, (err, readStream) => { if (err) { __logger.error('Error opening read stream:', err); reject(err); return; } const filePath = path.join(extractDir, entry.fileName); const dirPath = path.dirname(filePath); // Ensure directory exists fs.mkdirSync(dirPath, { recursive: true }); const writeStream = createWriteStream(filePath); readStream.pipe(writeStream); writeStream.on('close', () => { __logger.info(`Extracted: ${entry.fileName}`); zipfile.readEntry(); }); writeStream.on('error', (err) => { __logger.error('Error writing to file:', err); reject(err); }); }); } }); zipfile.on('end', () => { __logger.info('Extraction completed'); resolve(); }); zipfile.on('error', (err) => { __logger.error('Error processing zip file:', err); reject(err); }); }); }); } }