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