@trap_stevo/filetide
Version:
Revolutionizing real-time file transfer with seamless, instant communication across any device. Deliver files instantly, regardless of platform, and experience unparalleled speed and control in managing transfers. Elevate your file-sharing capabilities wi
288 lines (287 loc) • 11.8 kB
JavaScript
"use strict";
const readline = require("readline");
const chalk = require("chalk");
const {
FileTideDebugUtilityManager
} = require("../HUDManagers/FileTideDebugUtilityManager.js");
const {
FileNetUtilityManager
} = require("../HUDManagers/FileNetUtilityManager");
class ConsoleProgressBarManager {
constructor(tasks = [], options = {}) {
const rows = process.stdout.rows || 24;
this.visibleBars = rows - 3;
this.currentPage = 0;
this.barsPerPage = this.visibleBars;
this.maxCompletionFeedSize = 5;
this.completionTimeout = 5000;
this.completionFeed = [];
this.completedTasksCount = 0;
this.totalTasks = tasks.length;
this.taskBars = [];
this.options = options;
this.completionMessage = options.completionMessage || "Successfully processed all tasks!";
this.completionMessageColor = options.completionMessageColor || chalk.green;
this.allTasksCompleted = false;
this.taskBars = tasks.map((task, index) => this.createTaskBar(task, index));
}
createTaskBar(task, index) {
const defaultOptions = {
barLength: 40,
filledChar: ">",
unfilledChar: " ",
barColor: chalk.hex("#00CED1").bold,
taskNameColor: chalk.hex("#007B7F").bold,
taskCompletedColor: chalk.hex("#2ED573").bold,
sizeTransferredColor: chalk.hex("#5ECAFF"),
totalSizeColor: chalk.hex("#00FFFF"),
taskETAColor: chalk.hex("#00BFFF"),
speedColor: chalk.hex("#90E0EF"),
percentageColor: chalk.hex("#1A936F").bold,
dynamicUnits: true
};
const settings = {
...defaultOptions,
...this.options
};
const newBar = {
taskName: task.name,
totalSize: task.size,
current: 0,
startTime: Date.now(),
taskIndex: index,
completed: false,
redraw: () => {
if (!isNaN(newBar.taskIndex) && !isNaN(this.barsPerPage) && process.stdout.isTTY) {
readline.cursorTo(process.stdout, 0, newBar.taskIndex % this.barsPerPage);
process.stdout.clearLine();
}
if (newBar.completed) {
process.stdout.write(settings.taskCompletedColor(`${newBar.taskName}: Completed!`));
return;
}
const percentage = newBar.current / newBar.totalSize * 100;
const elapsedTime = (Date.now() - newBar.startTime) / 1000;
const speed = newBar.current / elapsedTime;
const speedData = FileNetUtilityManager.getFormattedSize(speed, settings.dynamicUnits);
const timeLeft = (newBar.totalSize - newBar.current) / (speed || 1);
newBar.progress = percentage;
newBar.timeLeft = timeLeft;
newBar.speed = speed;
const filledLength = Math.round(settings.barLength * (newBar.current / newBar.totalSize));
const bar = settings.barColor(settings.filledChar.repeat(filledLength)) + settings.unfilledChar.repeat(settings.barLength - filledLength);
try {
process.stdout.write(`${settings.taskNameColor(newBar.taskName)} > ${settings.totalSizeColor(FileNetUtilityManager.getFormattedSize(newBar.totalSize, settings.dynamicUnits))} | ${settings.sizeTransferredColor(FileNetUtilityManager.getFormattedSize(newBar.current, settings.dynamicUnits))} ${settings.speedColor(`${speedData}/s`)} | ${settings.taskETAColor(FileNetUtilityManager.convertSeconds(timeLeft.toFixed(2)))} [${bar}] ${settings.percentageColor(percentage.toFixed(2) + "%")}`);
} catch (error) {
console.log(error);
}
},
update: amount => {
newBar.current += amount;
if (newBar.current > newBar.totalSize) {
newBar.current = newBar.totalSize;
}
const startIndex = this.currentPage * this.barsPerPage;
const endIndex = startIndex + this.barsPerPage;
if (newBar.taskIndex >= startIndex && newBar.taskIndex < endIndex) {
newBar.redraw();
}
},
set: amount => {
newBar.current = amount;
if (newBar.current > newBar.totalSize) {
newBar.current = newBar.totalSize;
}
const startIndex = this.currentPage * this.barsPerPage;
const endIndex = startIndex + this.barsPerPage;
if (newBar.taskIndex >= startIndex && newBar.taskIndex < endIndex) {
newBar.redraw();
}
},
complete: () => {
newBar.completed = true;
this.completedTasksCount++;
if (this.completionFeed.length >= this.maxCompletionFeedSize) {
this.completionFeed.shift();
}
this.completionFeed.push(newBar.taskName);
newBar.redraw();
setTimeout(() => {
this.completionFeed = this.completionFeed.filter(task => task !== newBar.taskName);
}, this.completionTimeout);
FileTideDebugUtilityManager.log("notice", true, `Tasks Completion Status ~\n\n\tTasks ~ (${this.completedTasksCount}/${this.totalTasks})`);
if (this.completedTasksCount === this.totalTasks) {
FileTideDebugUtilityManager.log("notice", true, `All Tasks Complete!`);
this.allTasksCompleted = true;
this.exitInputListener();
this.displayPage();
this.displayCompletionMessage();
setTimeout(() => {
this.clearTaskBars();
}, this.completionTimeout);
}
}
};
return newBar;
}
addTask(task) {
const index = this.taskBars.length;
const newTaskBar = this.createTaskBar(task, index);
this.taskBars.push(newTaskBar);
this.totalTasks++;
}
updateTaskProgress(taskName, amount) {
const taskBar = this.taskBars.find(bar => bar.taskName === taskName);
if (taskBar) {
taskBar.update(amount);
try {
if (taskBar.current >= taskBar.totalSize && taskBar.complete) {
taskBar.complete();
}
} catch (error) {}
} else {
console.log(chalk.red(`Task ${taskName} not found.`));
}
}
setTaskProgress(taskName, amount) {
const taskBar = this.taskBars.find(bar => bar.taskName === taskName);
if (taskBar) {
taskBar.set(amount);
if (taskBar.current >= taskBar.totalSize) {
taskBar.complete();
}
} else {
console.log(chalk.red(`Task ${taskName} not found.`));
}
}
getCurrentStats() {
const completedTasks = this.taskBars.filter(bar => bar.completed).length;
const totalTasks = this.taskBars.length;
const overallProgress = totalTasks === 0 ? 0 : this.taskBars.reduce((acc, bar) => acc + bar.current / bar.totalSize * 100, 0) / totalTasks;
const stats = {
completedTasks,
totalTasks,
overallProgress: `${overallProgress.toFixed(2)}%`,
taskDetails: this.taskBars.map(bar => ({
taskName: bar.taskName,
progress: `${(bar.current / bar.totalSize * 100).toFixed(2)}%`,
completed: bar.completed,
currentSize: FileNetUtilityManager.getFormattedSize(bar.current, true),
totalSize: FileNetUtilityManager.getFormattedSize(bar.totalSize, true),
speed: `${FileNetUtilityManager.getUnitData(bar.speed, true).current} ${FileNetUtilityManager.getUnitData(bar.speed, true).unit}/s`,
timeLeft: FileNetUtilityManager.convertSeconds(bar.timeLeft.toFixed(2))
}))
};
return stats;
}
getTaskBar(taskID) {
if (typeof taskID === "string") {
return this.taskBars.find(bar => bar.taskName === taskID) || null;
} else if (typeof taskID === "number") {
return this.taskBars[taskID] || null;
}
return null;
}
clearTaskBars() {
this.taskBars = [];
this.totalTasks = 0;
this.completedTasksCount = 0;
this.completionFeed = [];
this.allTasksCompleted = false;
}
clearTaskBar(taskID) {
let taskIndex = null;
if (typeof taskID === "string") {
taskIndex = this.taskBars.findIndex(bar => bar.taskName === taskID);
} else if (typeof taskID === "number") {
taskIndex = identifier;
}
if (taskIndex !== null && taskIndex >= 0 && taskIndex < this.taskBars.length) {
this.taskBars.splice(taskIndex, 1);
this.totalTasks--;
return true;
}
return false;
}
clearPage() {
for (let i = 0; i < this.barsPerPage + 2; i++) {
readline.cursorTo(process.stdout, 0, i);
if (process.stdout.isTTY) {
process.stdout.clearLine();
}
}
}
displayPage(customPagePrefix = "Page", bottomMessage, bottomMessageColor = chalk.gray) {
this.clearPage();
const startIndex = this.currentPage * this.barsPerPage;
const endIndex = startIndex + this.barsPerPage;
this.taskBars.slice(startIndex, endIndex).forEach(bar => {
bar.redraw();
});
if (!this.allTasksCompleted) {
this.redrawCompletionFeed(customPagePrefix, bottomMessage, bottomMessageColor);
}
}
redrawCompletionFeed(customPagePrefix = "Page", bottomMessage, pageFooterMessageColor = chalk.blue, bottomMessageColor = chalk.gray, recentlyCompletedColor = chalk.green) {
const bottomPosition = this.barsPerPage;
if (!isNaN(bottomPosition) && process.stdout.isTTY) {
readline.cursorTo(process.stdout, 0, bottomPosition);
process.stdout.clearLine();
}
process.stdout.write(pageFooterMessageColor(`${customPagePrefix} ${this.currentPage + 1}/${Math.max(1, Math.ceil(this.taskBars.length / this.barsPerPage))} | Completed: ${this.completedTasksCount}/${this.totalTasks}`));
if (this.completionFeed.length > 0) {
process.stdout.write(recentlyCompletedColor(` | Recently completed: ${this.completionFeed.join(", ")}`));
}
if (!isNaN(bottomPosition) && process.stdout.isTTY) {
readline.cursorTo(process.stdout, 0, bottomPosition + 1);
process.stdout.clearLine();
}
if (bottomMessage) {
process.stdout.write(bottomMessageColor(bottomMessage));
}
}
listenForInput(customPagePrefix = "Page", bottomMessage, bottomMessageColor = chalk.gray, recentlyCompletedColor = chalk.green) {
if (!isNaN(this.barsPerPage) && process.stdout.isTTY) {
process.stdin.setRawMode(true);
process.stdin.resume();
}
process.stdin.setEncoding("utf-8");
this.inputListener = key => {
if (key === "\u0003") {
process.exit();
} else if (this.allTasksCompleted) {
this.exitInputListener();
} else if (key === "n" && this.currentPage < Math.ceil(this.taskBars.length / this.barsPerPage) - 1) {
this.currentPage++;
this.displayPage(customPagePrefix, bottomMessage, bottomMessageColor, recentlyCompletedColor);
} else if (key === "p" && this.currentPage > 0) {
this.currentPage--;
this.displayPage(customPagePrefix, bottomMessage, bottomMessageColor, recentlyCompletedColor);
}
};
process.stdin.on("data", this.inputListener);
}
exitInputListener() {
process.stdin.removeListener("data", this.inputListener);
FileTideDebugUtilityManager.log("notice", true, `Exiting input listener...`);
FileTideDebugUtilityManager.log("notice", true, `Process TTY ~ ${process.stdout.isTTY}`);
if (process.stdout.isTTY) {
process.stdin.setRawMode(false);
process.stdin.resume();
FileTideDebugUtilityManager.log("notice", true, `Resumed process.`);
}
FileTideDebugUtilityManager.log("notice", true, `Exited input listener.`);
}
displayCompletionMessage() {
const lastLine = Math.min(this.taskBars.length, this.barsPerPage);
readline.cursorTo(process.stdout, 0, lastLine);
FileTideDebugUtilityManager.log("notice", true, `Displaying task completion message...`);
FileTideDebugUtilityManager.log("notice", true, `Process TTY ~ ${process.stdout.isTTY}`);
if (process.stdout.isTTY) {
process.stdout.clearLine();
}
console.log(this.completionMessageColor(this.completionMessage));
}
}
;
module.exports = ConsoleProgressBarManager;