@controlplane/cli
Version:
Control Plane Corporation CLI
118 lines • 4.49 kB
JavaScript
"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