node-progress icon indicating copy to clipboard operation
node-progress copied to clipboard

Setting `curr` property breaks `:eta` and `:rate`

Open kaatt opened this issue 7 years ago • 2 comments

Setting the curr property breaks the :eta and :rate tokens.

To reproduce, edit examples/customtokens.js to include the curr property:

var bar = new ProgressBar(':percent eta: :eta downloading :current/:total :file :rate', {
  total: list.length, curr: 2
})
$ node examples/customtokens.js # Before
30% eta: 2.4 downloading 3/10 image03.jpg 3
^C
$ node examples/customtokens.js # After
100% eta: 0.0 downloading 10/10 image10.jpg NaN

:eta is always 0.0 and :rate is NaN

The bug isn't present when curr: 0

kaatt avatar Aug 12 '17 12:08 kaatt

Experiencing this as well.

Workaround is not setting curr and then just ticking the bar the value that would have been set to curr. Not great but not bad for long-running operations.

FoxxMD avatar Aug 24 '17 02:08 FoxxMD

The problem is that the library doesn't record the download start time when you specify curr. When that's fixed, the rate and eta calculations will need some work to take a starting curr value into account, too.

Workaround

The most basic workaround is to set the ProgressBar instance's start attribute to Date.now(). That'll keep :rate and :eta from erroring, but the calculations will act like you made curr amount of progress in zero time at an infinite rate, and it'll take a long time for the rate and ETA to settle.

Here's a workaround using custom tokens :myRateKB and :myETA. I'm displaying file transfer progress. The downit library provides a progress callback with total-bytes-received in gotBytes, and I'm diffing that value against the last-seen gotBytes to get a delta to feed to bar.tick().

  const lastDownloadSize = startingFileDiskSize;

  bar = new ProgressBar(`  [:bar] :myRateKB KiBps :percent :myETAs remaining`, {
    width: 40,
    curr: startingFileDiskSize,
    total: remoteSize
  });
  
  // Just setting `bar.start` will make :rate and :eta work, but will act like
  // the first `curr` bytes were transferred in zero time at infinite rate.
  bar.start = Date.now();

  downit(url, outPath, {
    onprogress: gotBytes => {
      const elapsedSecs = (Date.now() - bar.start) / 1000;
      const sessionTotalSize = remoteSize - startingFileDiskSize;
      const sessionProgress = gotBytes - startingFileDiskSize;
      bar.tick(gotBytes - lastDownloadSize, {
        myRateKB: Math.round((sessionProgress / 1024) / elapsedSecs),
        myETA: Math.round(elapsedSecs * (sessionTotalSize / sessionProgress - 1))
      });
      lastDownloadSize = got;
    }
  });

mildmojo avatar Feb 24 '20 05:02 mildmojo