UNPKG

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
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