UNPKG

@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
"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;