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.

85 lines 3.43 kB
import { abortableSleep } from "./abortableSleep.js"; import WriterIsClosedError from "../errors/writer-is-closed-error.js"; export class BytesWriteDebounce { _options; _writeChunks = []; _lastWriteTime = Date.now(); _totalSizeOfChunks = 0; _checkWriteInterval = false; _abortSleep = new AbortController(); _finished = false; constructor(_options) { this._options = _options; } async addChunk(index, buffers) { if (this._finished) { throw new WriterIsClosedError("Cannot write to a finished stream"); } let writeIndex = index; for (const buffer of buffers) { this._writeChunks.push({ index: writeIndex, buffer }); this._totalSizeOfChunks += buffer.length; writeIndex += buffer.length; } await this._writeIfNeeded(); this.checkIfWriteNeededInterval(); } async _writeIfNeeded() { if (this._totalSizeOfChunks >= this._options.maxSize || Date.now() - this._lastWriteTime >= this._options.maxTime) { await this.writeAll(); } } async checkIfWriteNeededInterval() { if (this._checkWriteInterval) { return; } this._checkWriteInterval = true; while (this._writeChunks.length > 0 && !this._finished) { await this._writeIfNeeded(); const timeUntilMaxLimitAfterWrite = this._options.maxTime - (Date.now() - this._lastWriteTime); await abortableSleep(Math.max(timeUntilMaxLimitAfterWrite, 0), this._abortSleep.signal); } this._checkWriteInterval = false; } writeAll() { if (this._writeChunks.length === 0) { return; } this._writeChunks = this._writeChunks.sort((a, b) => a.index - b.index); const firstWrite = this._writeChunks[0]; let writeIndex = firstWrite.index; let buffers = [firstWrite.buffer]; let buffersTotalLength = firstWrite.buffer.length; const writePromises = []; for (let i = 1; i < this._writeChunks.length; i++) { const nextWriteLocation = writeIndex + buffersTotalLength; const currentWrite = this._writeChunks[i]; if (currentWrite.index < nextWriteLocation) { // overlapping, prefer the last buffer (newer data) const lastBuffer = buffers.pop(); buffers.push(currentWrite.buffer); buffersTotalLength += currentWrite.buffer.length - lastBuffer.length; } else if (nextWriteLocation === currentWrite.index) { buffers.push(currentWrite.buffer); buffersTotalLength += currentWrite.buffer.length; } else { writePromises.push(this._options.writev(writeIndex, buffers)); writeIndex = currentWrite.index; buffers = [currentWrite.buffer]; buffersTotalLength = currentWrite.buffer.length; } } writePromises.push(this._options.writev(writeIndex, buffers)); this._writeChunks = []; this._totalSizeOfChunks = 0; this._lastWriteTime = Date.now(); return Promise.all(writePromises); } writeAllAndFinish() { this._finished = true; this._abortSleep.abort(); return this.writeAll(); } } //# sourceMappingURL=BytesWriteDebounce.js.map