61 lines
1.5 KiB
JavaScript
61 lines
1.5 KiB
JavaScript
import stream from 'node:stream';
|
|
|
|
const TransformStream = stream.Transform;
|
|
|
|
class ProgressStream extends TransformStream {
|
|
#options;
|
|
#transferred;
|
|
#delta;
|
|
#started;
|
|
#startTime;
|
|
#interval;
|
|
|
|
constructor(options) {
|
|
super();
|
|
this.#options = Object.assign({ interval: 10 * 1000 }, options);
|
|
this.#transferred = 0;
|
|
this.#delta = 0;
|
|
this.#started = false;
|
|
this.#startTime = null;
|
|
this.#interval = null;
|
|
}
|
|
|
|
stats() {
|
|
const duration = Date.now() - this.#startTime; // this is not at _stop time because other streams in pipeline might have to be taken into account
|
|
return { startTime: this.#startTime, duration, transferred: this.#transferred };
|
|
}
|
|
|
|
_start() {
|
|
this.#startTime = Date.now();
|
|
this.#started = true;
|
|
this.#interval = setInterval(() => {
|
|
const speed = this.#delta * 1000 / this.#options.interval;
|
|
this.#delta = 0;
|
|
this.emit('progress', { speed, transferred: this.#transferred });
|
|
}, this.#options.interval);
|
|
}
|
|
|
|
_stop() {
|
|
clearInterval(this.#interval);
|
|
}
|
|
|
|
_transform(chunk, encoding, callback) {
|
|
if (!this.#started) this._start();
|
|
this.#transferred += chunk.length;
|
|
this.#delta += chunk.length;
|
|
callback(null, chunk);
|
|
}
|
|
|
|
_flush(callback) {
|
|
this._stop();
|
|
callback(null);
|
|
}
|
|
|
|
_destroy(error, callback) {
|
|
this._stop();
|
|
callback(error);
|
|
}
|
|
}
|
|
|
|
export default ProgressStream;
|