ipull
Version:
The only file downloader you'll ever need. For node.js and the browser, CLI and library for fast and reliable file downloads.
89 lines • 3.66 kB
JavaScript
import { DownloadStatus } from "./progress-status-file.js";
import sleep from "sleep-promise";
const BASE_AVERAGE_SPEED_TIME = 1000;
const AVERAGE_SPEED_TIME = 1000 * 8;
const ALLOW_SPEED_DECREASE_PERCENTAGE = 10;
const ADD_MORE_PARALLEL_IF_SPEED_INCREASE_PERCENTAGE = 10;
export class DownloaderProgramManager {
_program;
_download;
// date, speed
_speedHistory = [];
_lastResumeDate = 0;
_lastAverageSpeed = 0;
_increasePaused = false;
_removeEvent;
constructor(_program, _download) {
this._program = _program;
this._download = _download;
this._initEvents();
}
_initEvents() {
let lastTransferredBytes = 0;
let lastTransferredBytesDate = 0;
let watNotActive = true;
const progressEvent = (event) => {
const now = Date.now();
if (event.retrying || event.downloadStatus != DownloadStatus.Active) {
watNotActive = true;
}
else {
if (watNotActive) {
this._lastResumeDate = now;
watNotActive = false;
}
const isTimeToCalculate = lastTransferredBytesDate + BASE_AVERAGE_SPEED_TIME < now;
if (lastTransferredBytesDate === 0 || isTimeToCalculate) {
if (isTimeToCalculate) {
const speedPerSec = event.transferredBytes - lastTransferredBytes;
this._speedHistory.push([now, speedPerSec]);
}
lastTransferredBytesDate = now;
lastTransferredBytes = event.transferredBytes;
}
}
const deleteAllBefore = now - AVERAGE_SPEED_TIME;
this._speedHistory = this._speedHistory.filter(([date]) => date > deleteAllBefore);
if (!watNotActive && now - this._lastResumeDate > AVERAGE_SPEED_TIME) {
this._checkAction();
}
};
this._download.on("progress", progressEvent);
this._removeEvent = () => this._download.off("progress", progressEvent);
}
_calculateAverageSpeed() {
const totalSpeed = this._speedHistory.reduce((acc, [, speed]) => acc + speed, 0);
return totalSpeed / (this._speedHistory.length || 1);
}
async _checkAction() {
const lastAverageSpeed = this._lastAverageSpeed;
const newAverageSpeed = this._calculateAverageSpeed();
const speedDecreasedOK = (lastAverageSpeed - newAverageSpeed) / newAverageSpeed * 100 > ALLOW_SPEED_DECREASE_PERCENTAGE;
if (!speedDecreasedOK) {
this._lastAverageSpeed = newAverageSpeed;
}
if (this._increasePaused || newAverageSpeed > lastAverageSpeed || speedDecreasedOK) {
return;
}
this._increasePaused = true;
this._program.incParallelStreams();
let sleepTime = AVERAGE_SPEED_TIME;
while (sleepTime <= AVERAGE_SPEED_TIME) {
await sleep(sleepTime);
sleepTime = Date.now() - this._lastResumeDate;
}
const newSpeed = this._calculateAverageSpeed();
const bestLastSpeed = Math.max(newAverageSpeed, lastAverageSpeed);
const speedIncreasedOK = newSpeed > bestLastSpeed && (newSpeed - bestLastSpeed) / bestLastSpeed * 100 > ADD_MORE_PARALLEL_IF_SPEED_INCREASE_PERCENTAGE;
if (speedIncreasedOK) {
this._increasePaused = false;
}
else {
this._program.decParallelStreams();
}
}
close() {
this._removeEvent?.();
}
}
//# sourceMappingURL=downloaderProgramManager.js.map