UNPKG

@controlplane/cli

Version:

Control Plane Corporation CLI

118 lines 4.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TarFileTransfer = void 0; const path = require("path"); const fs = require("fs"); const tar = require("tar-stream"); const progress_bar_1 = require("./progress-bar"); class TarFileTransfer { constructor(srcPath, destPath, ws) { // Private Properties this.openStreams = 0; this.progressBar = new progress_bar_1.ProgressBar(); this.totalSize = 0; // - Readonly Properties this.srcPath = path.normalize(srcPath); this.destPath = path.normalize(destPath); this.ws = ws; } // Public Methods // isComplete() { return this.progressBar.isComplete(); } stopProgress() { this.progressBar.stop(); } transfer() { // Initialize tar-stream pack const pack = tar.pack(); // Subscribe to the data event to send the tar archive as a stream to the client pack.on('data', (chunk) => { this.ws.send(chunk, { fin: false, binary: true }); }); // Subscribe to the end event to signal an EOF pack.on('end', () => { this.ws.send(Buffer.from([]), { fin: true }); }); // Subscribe to the error event to handle errors pack.on('error', (err) => { if (err) { throw err; } }); // Get the last portion of the destination path const destFile = path.basename(this.destPath); // Pack file or directory this.packFileOrDirectory(this.srcPath, destFile, pack); // After opening all the necessary streams, periodically check if they were closed this.checkFinalization(pack); } updateProgress(bytes) { this.progressBar.update(bytes); } // Private Methods // checkFinalization(pack) { if (this.openStreams == 0) { pack.finalize(); // Add 1024 bytes to mark the end of the tar archive this.totalSize += 1024; // Start progress bar this.progressBar.start(this.totalSize); return; } setTimeout(() => this.checkFinalization(pack), 100); } packFileOrDirectory(srcPath, destFile, pack) { // Get the file statistics for the given file path const stat = fs.statSync(srcPath); // Add the 512-byte header per file / directory this.totalSize += 512; // Check if the current path is a directory if (stat.isDirectory()) { // Add an entry for the directory to the tar archive pack.entry({ name: destFile + '/', type: 'directory' }); // Read all files and directories inside the current directory const subFileNames = fs.readdirSync(srcPath); for (const srcSubFileName of subFileNames) { // Recursively add each file or directory to the tar archive this.packFileOrDirectory(path.join(srcPath, srcSubFileName), path.join(destFile, srcSubFileName), pack); } return; } else if (stat.isSymbolicLink()) { // Add an entry for the symbolic link to the tar archive const linkTarget = fs.readlinkSync(srcPath); pack.entry({ name: destFile, type: 'symlink', linkname: linkTarget }, (err) => { if (err) { throw err; } }); return; } // Increase the amount of open streams this.openStreams++; // Create a new pack entry const headers = { name: destFile, size: stat.size }; const entry = pack.entry(headers, (err) => { if (err) { throw err; } // Add the actual file size this.totalSize += headers.size; // Add padding to the nearest 512 bytes if (headers.size % 512 !== 0) { this.totalSize += 512 - (headers.size % 512); } }); // Create a read stream out of the file const fileStream = fs.createReadStream(srcPath); // Pipe the file stream to the tar entry fileStream.pipe(entry); // Decrease the amount of open streams after streaming the file fileStream.on('close', () => { this.openStreams--; }); } } exports.TarFileTransfer = TarFileTransfer; //# sourceMappingURL=tar-file-transfer.js.map