Elius94 / console-gui-tools

A simple library to draw option menu or other popup inputs and layout on Node.js console.
MIT License
106 stars 17 forks source link

[Bug]: Adding lots of Progress produces MaxListenersExceededWarning #86

Closed rjjrbatarao closed 1 month ago

rjjrbatarao commented 1 month ago

What happened?

Testing the HTOP sample works but when I set the logLocation: "popup" to 1 then it showed the error on the logs section MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 keypress listeners | MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 mouseevent listeners. I tried reducing the numberOfCores and the problem got away with < 9, its around 9 instances of Progress

What should have happened?

there should be no nodejs warning

Code

const { ConsoleManager, PageBuilder, ConfirmPopup, FileSelectorPopup, Progress, } = require("console-gui-tools");

const os = require("node:os"); const process = require("node:process"); //const si = require("systeminformation");

const opt = { title: "SYSTEM INFO", // Title of the console logPageSize: 30, // Number of lines to show in logs page logLocation: 1, // Location of the logs page enableMouse: false, // Enable mouse support layoutOptions: { type: "single", boxed: true, // Set to true to enable boxed layout showTitle: true, // Set to false to hide title changeFocusKey: "ctrl+l", // Change layout with ctrl+l to switch to the logs page type: "double", // Set to 'double' to enable double layout direction: "vertical", // Set to 'horizontal' to enable horizontal layout boxColor: "yellow", boxStyle: "bold", }, };

// si.currentLoad().then((data) => { // console.log(JSON.stringify(data)); // });

const GUI = new ConsoleManager(opt);

const numberOfCores = os.cpus().length; const cores = [];

for (let i = 0; i < numberOfCores; i++) { cores.push( new Progress({ id: htop-cpu-${i}, x: 2, y: 1 + i, interactive: false, draggable: false, label: ${i}, length: 40, min: 0, max: 100, style: { boxed: true, theme: "htop", showMinMax: false, showValue: false, }, }) ); }

const mem = new Progress({ id: "htop-mem", x: 2, y: 1 + numberOfCores, label: "Mem", length: 40, min: 0, max: os.totalmem() / (1024 1024 1024), unit: "G", style: { boxed: true, theme: "htop", showMinMax: false, }, });

//Create function to get CPU information function cpuAverage(core) { //Initialise sum of idle and time of cores and fetch CPU info let totalIdle = 0, totalTick = 0;

//Select CPU core const cpu = os.cpus()[core];

//Total up the time in the cores tick for (let i = 0, len = Object.keys(cpu.times).length; i < len; i++) { totalTick += Object.values(cpu.times)[i]; }

//Total up the idle time of the core totalIdle += cpu.times.idle;

//Return the average Idle and Tick times return { idle: totalIdle, total: totalTick }; }

// clientManager.on("send", (data) => { // console.log("send: ", data); // });

function getCPULoadAVG(core, avgTime = 1000, delay = 500) { return new Promise((resolve, reject) => { const n = ~~(avgTime / delay); if (n <= 1) { reject("Error: interval to small"); } let i = 0; const samples = []; const avg1 = cpuAverage(core);

const interval = setInterval(() => {
  //GUI.log("CPU Interval: " + i)

  if (i >= n) {
    clearInterval(interval);
    resolve(
      ~~((samples.reduce((a, b) => a + b, 0) / samples.length) * 100)
    );
  }

  const avg2 = cpuAverage(core);
  const totalDiff = avg2.total - avg1.total;
  const idleDiff = avg2.idle - avg1.idle;

  samples[i] = 1 - idleDiff / totalDiff;
  i++;
}, delay);

}); }

const getSystemInfo = async () => { const coresPercent = [];

for (let i = 0; i < numberOfCores; i++) { const load = await getCPULoadAVG(i).catch((err) => console.error(err)); coresPercent.push(load); } const memUsage = os.totalmem() - os.freemem(); return { cpuUsage: coresPercent, memUsage, }; };

setInterval(() => { getSystemInfo().then((info) => { info.cpuUsage.forEach((core, i) => { cores[i].setValue(core); }); mem.setValue(info.memUsage / (1024 1024 1024)); }); }, 1000);

/**

GUI.on("exit", () => { closeApp(); });

GUI.on("keypressed", (key) => { switch (key.name) { case "f": new FileSelectorPopup({ id: "popupFileManager", title: "File Manager", basePath: "./", }).show(); break; case "q": new ConfirmPopup({ id: "popupQuit", title: "Are you sure you want to quit?", }) .show() .on("confirm", () => closeApp()); break; default: break; } });

const closeApp = () => { console.clear(); process.exit(); };

GUI.refresh();

const drawGui = (p) => { GUI.setPage(p); GUI.refresh(); };

updateConsole();

Library Version

^3.5.0

Node Version

v16.13.0 and v21.7.3

What operating system are you using?

Windows

Terminal

git bash, cmdr

Interest to fix the bug

Elius94 commented 1 month ago

Hey @rjjrbatarao thank you a lot for reporting me this bug! I think that it's a structural bug in some control widget! I'm working on it

rjjrbatarao commented 1 month ago

thank you for this I'll test it right away :)