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.
152 lines • 5.94 kB
JavaScript
import { EventEmitter } from "eventemitter3";
import TransferStatistics from "./transfer-statistics.js";
import { createFormattedStatus } from "./format-transfer-status.js";
import ProgressStatusFile, { DownloadStatus } from "../download-engine/download-file/progress-status-file.js";
export default class ProgressStatisticsBuilder extends EventEmitter {
_engines = new Set();
_activeTransfers = {};
_totalBytes = 0;
_transferredBytes = 0;
_latestEngine = null;
/**
* @internal
*/
_totalDownloadParts = 0;
_activeDownloadPart = 0;
_startTime = 0;
_statistics = new TransferStatistics();
_lastStatus = null;
_downloadStatus = null;
_endTime = 0;
_downloadId = "";
_allFileNames = "";
_retrying = 0;
_retryingTotalAttempts = 0;
_streamsNotResponding = 0;
constructor() {
super();
this.createStatus(0);
}
get downloadStatus() {
return this._downloadStatus;
}
set downloadStatus(status) {
if (this._downloadStatus === status)
return;
this._downloadStatus = status;
if ([DownloadStatus.Finished, DownloadStatus.Cancelled, DownloadStatus.Error].includes(status)) {
this._endTime = Date.now();
this._lastStatus = {
...this._lastStatus,
downloadStatus: status,
endTime: this._endTime
};
}
this.emit("progress", this._lastStatus);
}
get totalBytes() {
return this._totalBytes;
}
get transferredBytesWithActiveTransfers() {
return this._transferredBytes + Object.values(this._activeTransfers)
.reduce((acc, bytes) => acc + bytes, 0);
}
get status() {
return this._lastStatus;
}
add(engine, sendProgress = true) {
const latestStatus = engine.status;
this._engines.add(engine);
this._latestEngine = engine;
this._totalBytes += engine.downloadSize;
const index = this._engines.size - 1;
const downloadPartStart = this._totalDownloadParts;
this._totalDownloadParts += latestStatus.totalDownloadParts;
this._downloadId += latestStatus.downloadId;
this._allFileNames += this._allFileNames ? ", " + latestStatus.fileName : latestStatus.fileName;
if (latestStatus.downloadStatus === DownloadStatus.Active || this._downloadStatus === null) {
this._downloadStatus = latestStatus.downloadStatus;
}
let lastRetrying = 0;
let lastRetryingTotalAttempts = 0;
let lastStreamsNotResponding = 0;
engine.on("progress", (data) => {
const retrying = Number(data.retrying);
this._retrying += retrying - lastRetrying;
lastRetrying = retrying;
this._retryingTotalAttempts += data.retryingTotalAttempts - lastRetryingTotalAttempts;
lastRetryingTotalAttempts = data.retryingTotalAttempts;
this._streamsNotResponding += data.streamsNotResponding - lastStreamsNotResponding;
lastStreamsNotResponding = data.streamsNotResponding;
this._sendProgress(data, index, downloadPartStart);
});
engine.on("finished", () => {
delete this._activeTransfers[index];
this._transferredBytes += engine.downloadSize;
});
if (sendProgress) {
this._sendProgress(latestStatus, index, downloadPartStart);
}
}
/**
* @internal
*/
_sendLatestProgress() {
if (!this._latestEngine)
return;
const engine = this._latestEngine;
const status = engine.status;
this._sendProgress(status, this._engines.size - 1, this._totalDownloadParts - status.totalDownloadParts);
}
_sendProgress(data, index, downloadPartStart) {
this._startTime ||= data.startTime;
this._activeTransfers[index] = data.transferredBytes;
if (downloadPartStart + data.downloadPart > this._activeDownloadPart) {
this._activeDownloadPart = downloadPartStart + data.downloadPart;
}
this.emit("progress", this.createStatus(index, data));
}
createStatus(index, data) {
const progress = this._statistics.updateProgress(this.transferredBytesWithActiveTransfers, this.totalBytes);
const optionsForMultiDownload = this._engines.size <= 1 && data ? data : {
comment: "",
transferAction: "Transferring",
downloadStatus: this._downloadStatus,
endTime: this._endTime,
downloadFlags: []
};
return this._lastStatus = {
...createFormattedStatus({
...optionsForMultiDownload,
...progress,
downloadId: this._downloadId,
downloadPart: this._activeDownloadPart,
totalDownloadParts: this._totalDownloadParts,
startTime: this._startTime,
fileName: this._allFileNames,
retrying: this._retrying > 0,
retryingTotalAttempts: this._retryingTotalAttempts,
streamsNotResponding: this._streamsNotResponding
}),
index
};
}
static oneStatistics(engine) {
const progress = engine.status;
const statistics = TransferStatistics.oneStatistics(progress.transferredBytes, progress.totalBytes);
return createFormattedStatus({
...progress,
...statistics
});
}
static loadingStatusEmptyStatistics() {
const statistics = TransferStatistics.oneStatistics(0, 0);
const status = new ProgressStatusFile(0, "???");
status.downloadStatus = DownloadStatus.Loading;
return createFormattedStatus({
...status,
...statistics
});
}
}
//# sourceMappingURL=progress-statistics-builder.js.map