Socket
Socket
Sign inDemoInstall

status-bar

Package Overview
Dependencies
1
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.2 to 1.0.0

255

lib/index.js

@@ -11,2 +11,52 @@ "use strict";

var storage = [" B ", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB", " ZiB",
" YiB"];
var speeds = ["B/s", "K/s", "M/s", "G/s", "T/s", "P/s", "E/s", "Z/s", "Y/s"];
var space = function (n, max){
n += "";
var spaces = max - n.length;
for (var i=0; i<spaces; i++){
n = " " + n;
}
return n;
};
var unit = function (n, arr, pow, decimals){
var chars = decimals ? 5 + decimals : 4;
if (n < pow) return space (n, chars) + arr[0];
var i = 1;
while (i < 9){
n /= pow;
if (n < pow) return space (n.toFixed (decimals), chars) + arr[i];
i++;
}
return ">=" + pow + arr[7];
};
var zero = function (n){
return n < 10 ? "0" + n : n;
};
module.exports.format = {
storage: function (b, decimals){
return unit (~~b, storage, 1024, decimals === undefined ? 1 : decimals);
},
speed: function (bps, decimals){
return unit (~~bps, speeds, 1000, decimals === undefined ? 1 : decimals);
},
time: function (s){
if (s === undefined) return "--:--";
if (s >= 86400000) return " > 1d";
if (s >= 3600000) return " > 1h";
var str;
var min = ~~(s/60);
var sec = ~~(s%60);
return zero (min) + ":" + zero (sec);
},
percentage: function (n){
return space (Math.round (n*100) + "%", 4);
}
};
var StatusBar = function (options){

@@ -16,33 +66,59 @@ if (options.total === undefined || options.total === null){

}
if (!options.render){
throw new Error ("Missing rendering function");
}
stream.Writable.call (this);
this._total = options.total;
this._frequency = options.frequency || null;
var me = this;
this.on ("unpipe", function (){
me.cancel ();
});
this._render = options.render;
this._frequency = options.frequency || 200;
this._finish = options.finish;
this._progress = pbf.create ({
completion: options.barCompletion,
incompletion: options.barIncompletion,
length: options.barLength
complete: options.progressBarComplete,
incomplete: options.progressBarIncomplete,
length: options.progressBarLength
});
this._current = 0;
this._timer = null;
this._total = ~~options.total;
this._renderTimer = null;
this._elapsedTimer = null;
this._start = 0;
this._chunkTimestamp = 0;
this._smooth = 0.005;
this._secondsWithoutUpdate = 0;
this.stats = {
total: this._total + ""
this._stats = {
currentSize: 0,
totalSize: this._total,
remainingSize: this._total,
speed: 0,
elapsedTime: 0
};
this._format ();
if (options.write){
this._render = options.write;
options.write.call (this);
if (this._frequency && this._total > 0){
var me = this;
this._timer = setInterval (function (){
options.write.call (me);
}, this._frequency);
}
var percentage;
if (this._total === 0){
percentage = 1;
this._stats.remainingTime = 0;
}else{
percentage = 0;
//Undefined remainingTime
}
this._stats.progressBar = this._progress.format (percentage);
this._stats.percentage = percentage;
//Render for the first time
this._render (this._stats);
if (this._frequency && this._total > 0){
//If the file has a size of 0 the update function is never called and the
//bar is never rendered again, so there's no need to create a timer
this._renderTimer = setInterval (function (){
me._render (me._stats);
}, this._frequency);
}
};

@@ -57,93 +133,55 @@

var space = function (n){
n += "";
while (n.length < 6){
n = " " + n;
}
return n;
};
var units = [" B ", " KiB", " MiB", " GiB", " TiB", " PiB", " EiB", " ZiB",
" YiB"];
var speeds = ["B/s", "K/s", "M/s", "G/s", "T/s", "P/s", "E/s", "Z/s", "Y/s"];
StatusBar.prototype._unit = function (n, arr, pow){
if (n < pow) return space (n) + arr[0];
var i = 1;
while (i < 9){
n /= pow;
if (n < pow) return space (n.toFixed (1)) + arr[i];
i++;
}
return ">=" + pow + arr[7];
};
StatusBar.prototype._formatSize = function (){
return this._unit (this._current, units, 1024);
};
StatusBar.prototype._formatSpeed = function (bytes){
if (bytes === undefined) return " 0B/s";
return this._unit (~~bytes, speeds, 1000);
};
var zero = function (n){
return n < 10 ? "0" + n : n;
};
StatusBar.prototype._formatTime = function (t){
if (t === undefined) return this._current === this._total ? "00:00" : "--:--";
var str;
if (t >= 86400000) return " > 1d";
if (t >= 3600000) return " > 1h";
t /= ~~1000;
var min = ~~(t/60);
var sec = ~~(t%60);
return zero (min) + ":" + zero (sec);
};
StatusBar.prototype._format = function (length){
StatusBar.prototype._updateStats = function (length){
var end = this._current === this._total;
var elapsed;
var now = Date.now ();
var end = this._current === this._total;
var n;
this.stats.current = this._current + "";
//The elapsed time needs to be calculated with a timer because if it's
//calculated using the elapsed time from the start of the transfer, if the
//transfer is hung up, the stat must continue to be updated each second
if (!this._elapsedTimer){
var me = this;
this._elapsedTimer = setInterval (function (){
//Wait 3 seconds before considering a transfer hang up
if (++me._secondsWithoutUpdate === 3){
me._stats.speed = 0;
me._stats.remainingTime = undefined;
}
me._stats.elapsedTime++;
}, 1000);
}
this.stats.size = this._formatSize ();
this._stats.currentSize = this._current;
this._stats.remainingSize = this._total - this._current;
this._stats.percentage = this._current/this._total;
this._stats.progressBar = this._progress.format (this._stats.percentage);
//The transfer speed is extrapolated from the time between chunks
//The speed and remaining time cannot be calculated only with the first packet
if (this._chunkTimestamp){
//The transfer speed is extrapolated from the time between chunks
elapsed = process.hrtime (this._chunkTimestamp);
//Elapsed in nanoseconds
elapsed = elapsed[0]*1e9 + elapsed[1];
if (!end){
//The last packet slows down the speed
this.stats.speed = this._formatSpeed ((length*1e9)/elapsed);
if (end){
this._stats.speed = 0;
}else{
//Bytes per second
var lastSpeed = (length*1e9)/elapsed;
this._stats.speed = ~~(this._smooth*lastSpeed +
(1 - this._smooth)*(this._stats.speed || lastSpeed));
}
this._chunkTimestamp = process.hrtime ();
}else{
this.stats.speed = this._formatSpeed ();
if (end){
this._stats.remainingTime = 0;
}else{
elapsed = Date.now () - this._start;
this._stats.remainingTime =
~~((0.001*elapsed*this._stats.remainingSize)/this._current) + 1;
}
}
//The estimated remaining time uses the current file size
if (this._start){
n = end ? 0 : 1000;
elapsed = now - this._start;
var remaining = this._total - this._current;
this.stats.eta = this._formatTime ((elapsed*remaining)/this._current + n);
}else{
this.stats.eta = this._formatTime ();
}
n = this._total === 0 ? 1 : this._current/this._total;
this.stats.progress = this._progress.format (n);
this.stats.percentage = Math.round (n*100) + "%";
while (this.stats.percentage.length !== 4){
this.stats.percentage = " " + this.stats.percentage;
}
};
StatusBar.prototype.clearInterval = function (){
clearInterval (this._timer);
StatusBar.prototype.cancel = function (){
clearInterval (this._renderTimer);
clearInterval (this._elapsedTimer);
};

@@ -154,22 +192,19 @@

this._secondsWithoutUpdate = 0;
//Allow any object with a length property
var length = chunk.length || chunk;
this._current += length;
this._format (length);
this._updateStats (length);
if (!this._chunkTimestamp){
this._chunkTimestamp = process.hrtime ();
}
//High resolution timer between packets
this._chunkTimestamp = process.hrtime ();
if (!this._render) return;
//Force a writing if there's no timer
if (!this._timer) return this._render ();
//Force a writing if the progress has finished and it has a timer
//Force a render if the transfer has finished
if (this._current === this._total){
this.clearInterval ();
this._render ();
this.cancel ();
this._render (this._stats);
if (this._finish) this._finish ();
}
};
{
"name": "status-bar",
"version": "0.0.2",
"version": "1.0.0",
"description": "A status bar for file transfers",

@@ -5,0 +5,0 @@ "keywords": ["status", "bar", "file", "transfer", "speed", "progress",

@@ -19,10 +19,11 @@ status-bar

total: size,
//Writing frequency
frequency: 200,
//Writing function
write: function (){
//Render function
render: function (stats){
//Print the status bar as you like
process.stdout.write (filename + " " + this.stats.size + " " +
this.stats.speed + " " + this.stats.eta + " [" + this.stats.progress +
"] " + this.stats.percentage);
process.stdout.write (filename + " " +
statusBar.format.storage (stats.currentSize) + " " +
statusBar.format.speed (stats.speed) + " " +
statusBar.format.time (stats.remainingTime) + " [" +
stats.progressBar + "] " +
statusBar.format.percentage (stats.percentage));
process.stdout.cursorTo (0);

@@ -33,3 +34,3 @@ }

//Update the status bar when you send or receive a chunk of a file
.on ("some-event", function (chunk){
obj.on ("some-event", function (chunk){
//You can pass any object that contains a length property or a simple number

@@ -48,4 +49,5 @@ bar.update (chunk);

- It doesn't print anything, it just formats the data and you decide how you want to print the status bar. Other modules similar to this use the `readline` module which is very unstable and may cause problems if you are already using a `readline` instance.
- You decide how to arrange the elements of the status bar. Because each element has a fixed length you can format the status bar very easily.
- It doesn't print anything, it just calculates and returns raw data and provides default formatting functions. Other modules similar to this force you to use their own formatting functions with the `readline` module, which is very unstable and may cause problems if you are already using a `readline` instance.
- The status bar can be displayed wherever you want, it is simply a string, so you can render it in the console, in HTML (probably with your own progress bar) sending it via websockets or with [node-webkit](https://github.com/rogerwang/node-webkit), etc.
- You decide how format and arrange the elements of the status bar. The default formatting functions have a fixed length, so you can format the status bar very easily.
- It is very easy to use. Just `pipe()` things to it!

@@ -62,2 +64,4 @@

```javascript
var statusBar = require ("status-bar");
var formatFilename = function (filename){

@@ -79,8 +83,16 @@ //80 - 59

var write = function (){
process.stdout.write (filename + " " + this.stats.size + " " +
this.stats.speed + " " + this.stats.eta + " [" +
this.stats.progress + "] " + this.stats.percentage);
var render = function (stats){
process.stdout.write (filename + " " +
statusBar.format.storage (stats.currentSize) + " " +
statusBar.format.speed (stats.speed) + " " +
statusBar.format.time (stats.remainingTime) + " [" +
stats.progressBar + "] " +
statusBar.format.percentage (stats.percentage));
process.stdout.cursorTo (0);
};
var bar = statusBar.create ({
total: ...,
render: render
});
```

@@ -95,8 +107,18 @@

```javascript
var write = function (){
process.stdout.write ("Receiving objects: " + this.stats.percentage.trim () +
" (" + this.stats.current + "/" + this.stats.total + "), " +
this.stats.size.trim () + " | " + this.stats.speed.trim ());
var statusBar = require ("status-bar");
var render = function (stats){
process.stdout.write ("Receiving objects: " +
statusBar.format.percentage (stats.percentage).trim () +
" (" + stats.currentSize + "/" + stats.totalSize + "), " +
statusBar.format.storage (stats.currentSize).trim () + " | " +
statusBar.format.speed (stats.speed).trim ());
process.stdout.cursorTo (0);
};
var bar = statusBar.create ({
total: ...,
render: render
});
```

@@ -107,2 +129,6 @@

- [_module_.create(options) : StatusBar](#create)
- [_module_.format.percentage(percentage) : String](#format-percentage)
- [_module_.format.speed(bytesPerSecond) : String](#format-speed)
- [_module_.format.storage(bytes) : String](#format-storage)
- [_module_.format.time(seconds) : String](#format-time)

@@ -122,94 +148,111 @@ #### Objects ####

- __total__ - _Number_
The total size of a file. This option is required.
- __barComplete__ - _String_
- __finish__ - _Function_
Function that is called when the file transfer has finished.
- __frequency__ - _Number_
The rendering frequency in milliseconds. It must be a positive value. Default is 200.
- __progressBarComplete__ - _String_
The character that shows completion progress. Default is `#`.
- __barIncomplete__ - _String_
- __progressBarIncomplete__ - _String_
The character that shows the remaining progress. Default is `·`.
- __barLength__ - _Number_
The length of the progress bar. Default is `24`.
- __frequency__ - _Number_
The writing frequency. If you don't configure a `write` function, this option is ignored. By default there's no value, so each time you call to [update()](#statusbar_update), the status bar is printed. This is the most accurate behaviour but it slows down the file transfer very much. I recommend to render the status bar every 200ms, remember that a status bar is purely informational.
- __write__ - _Function_
Function that is called when the status bar needs to be printed.
- __finish__ - _Function_
Function that is called when the file transfer has finished.
- __progressBarLength__ - _Number_
The length of the progress bar. Default is 24.
- __render__ - _Function_
Function that is called when the status bar needs to be printed. It is required. It receives the stats object as an argument. All of its properties contain raw data (except the progress bar), so you need to format them. You can use the default formatting functions.
Properties:
- __currentSize__ - _Number_
The current size in bytes.
- __remainingSize__ - _Number_
The remaining size in bytes.
- __totalSize__ - _Number_
The total size in bytes.
- __percentage__ - _Number_
The complete percentage. A number between 0 and 1.
- __speed__ - _Number_
The estimated current speed in bytes per second.
- __elapsedTime__ - _Number_
The elapsed time in seconds.
- __remainingTime__ - _Number_
The estimated remaining time in seconds. If the remaining time cannot be estimated because the status bar needs at least 2 chunks or because the transfer it's hung up, it returns `undefined`.
- __progressBar__ - _String_
The progress bar.
```
######··················
```
- __total__ - _Number_
The total size of the file. This option is required.
---
<a name="statusbar_object"></a>
__StatusBar__
<a name="format-percentage"></a>
___module_.format.percentage(percentage) : String__
__Methods__
The percentage must be a number between 0 and 1. Result string length: 4.
- [StatusBar#clearInterval() : undefined](#statusbar_clearinterval)
- [StatusBar#update(chunk) : undefined](#statusbar_update)
```javascript
console.log (statusBar.format.percentage (0.5));
// 50%
```
__Properties__
---
- [StatusBar#stats](#statusbar_stats)
<a name="format-speed"></a>
___module_.format.speed(bytesPerSecond) : String__
Speed in bytes per second. Result string length: 9.
```javascript
console.log (statusBar.format.speed (30098226));
// 30.1M/s
```
---
<a name="statusbar_clearinterval"></a>
__StatusBar#clearInterval() : undefined__
<a name="format-storage"></a>
___module_.format.storage(bytes) : String__
When you need to cancel the status bar rendering because the file transfer has been aborted due to an error or any other reason, call to this function to clear the timer. This is only needed when the `frequency` option is configured.
Result string length: 10.
```javascript
console.log (statusBar.format.storage (38546744));
// 36.8 MiB
```
---
<a name="statusbar_update"></a>
__StatusBar#update(chunk) : undefined__
<a name="format-time"></a>
___module_.format.time(seconds) : String__
Updates the status bar. The `chunk` can be any object with a length property or a simple number.
Result string length: 5 (_min_:_sec_). If `seconds` is undefined it prints `--:--`.
```javascript
console.log (statusBar.format.time (63));
//01:03
```
---
<a name="statusbar_stats"></a>
__StatusBar#stats__
<a name="statusbar_object"></a>
__StatusBar__
`stats` is an object that contains the current state of the status bar. It is updated each time you [update()](statusbar_update) the status bar. All the following properties are strings and most of them have a fixed length.
__Methods__
- __current__ - _String_
The current file size. Length: variable. Example:
- [StatusBar#cancel() : undefined](#statusbar_cancel)
- [StatusBar#update(chunk) : undefined](#statusbar_update)
```
1234
```
- __eta__ - _String_
The estimated remaining time. Length: 5. Example (_min_:_sec_):
---
```
01:45
```
- __percentage__ - _String_
The completion percentage. Length: 4. Example:
<a name="statusbar_cancel"></a>
__StatusBar#cancel() : undefined__
```
100%
```
- __progress__ - _String_
A progress bar with the current file completion. Length: configured with the `barLength` option. Example:
When you need to cancel the status bar rendering because the file transfer has been aborted due to an error or any other reason, call to this function to clear the timer. This is only needed when the `frequency` option is configured.
```
##########··············
```
- __size__ - _String_
The current formatted size of the file that is being received/sent. Length: 10. Example:
---
```
12.5 MiB
```
- __speed__ - _String_
The current file transfer speed. Length: 9. Example:
<a name="statusbar_update"></a>
__StatusBar#update(chunk) : undefined__
```
5.3M/s
```
- __total__ - _String_
The total file size. Length: variable. Example:
```
5678
```
Updates the status bar. The `chunk` can be any object with a length property or a simple number.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc