Source code

Revision control

Copy as Markdown

Other Tools

'use strict';
(function () {
// Fake setInterval-like functionality in environments that don't have it
class IntervalHandle {
constructor(callback, delayMs) {
this.callback = callback;
this.delayMs = delayMs;
this.cancelled = false;
Promise.resolve().then(() => this.check());
}
async check() {
while (true) {
await new Promise(resolve => step_timeout(resolve, this.delayMs));
if (this.cancelled) {
return;
}
this.callback();
}
}
cancel() {
this.cancelled = true;
}
}
let localSetInterval, localClearInterval;
if (typeof globalThis.setInterval !== "undefined" &&
typeof globalThis.clearInterval !== "undefined") {
localSetInterval = globalThis.setInterval;
localClearInterval = globalThis.clearInterval;
} else {
localSetInterval = function setInterval(callback, delayMs) {
return new IntervalHandle(callback, delayMs);
}
localClearInterval = function clearInterval(handle) {
handle.cancel();
}
}
class RandomPushSource {
constructor(toPush) {
this.pushed = 0;
this.toPush = toPush;
this.started = false;
this.paused = false;
this.closed = false;
this._intervalHandle = null;
}
readStart() {
if (this.closed) {
return;
}
if (!this.started) {
this._intervalHandle = localSetInterval(writeChunk, 2);
this.started = true;
}
if (this.paused) {
this._intervalHandle = localSetInterval(writeChunk, 2);
this.paused = false;
}
const source = this;
function writeChunk() {
if (source.paused) {
return;
}
source.pushed++;
if (source.toPush > 0 && source.pushed > source.toPush) {
if (source._intervalHandle) {
localClearInterval(source._intervalHandle);
source._intervalHandle = undefined;
}
source.closed = true;
source.onend();
} else {
source.ondata(randomChunk(128));
}
}
}
readStop() {
if (this.paused) {
return;
}
if (this.started) {
this.paused = true;
localClearInterval(this._intervalHandle);
this._intervalHandle = undefined;
} else {
throw new Error('Can\'t pause reading an unstarted source.');
}
}
}
function randomChunk(size) {
let chunk = '';
for (let i = 0; i < size; ++i) {
// Add a random character from the basic printable ASCII set.
chunk += String.fromCharCode(Math.round(Math.random() * 84) + 32);
}
return chunk;
}
function readableStreamToArray(readable, reader) {
if (reader === undefined) {
reader = readable.getReader();
}
const chunks = [];
return pump();
function pump() {
return reader.read().then(result => {
if (result.done) {
return chunks;
}
chunks.push(result.value);
return pump();
});
}
}
class SequentialPullSource {
constructor(limit, options) {
const async = options && options.async;
this.current = 0;
this.limit = limit;
this.opened = false;
this.closed = false;
this._exec = f => f();
if (async) {
this._exec = f => step_timeout(f, 0);
}
}
open(cb) {
this._exec(() => {
this.opened = true;
cb();
});
}
read(cb) {
this._exec(() => {
if (++this.current <= this.limit) {
cb(null, false, this.current);
} else {
cb(null, true, null);
}
});
}
close(cb) {
this._exec(() => {
this.closed = true;
cb();
});
}
}
function sequentialReadableStream(limit, options) {
const sequentialSource = new SequentialPullSource(limit, options);
const stream = new ReadableStream({
start() {
return new Promise((resolve, reject) => {
sequentialSource.open(err => {
if (err) {
reject(err);
}
resolve();
});
});
},
pull(c) {
return new Promise((resolve, reject) => {
sequentialSource.read((err, done, chunk) => {
if (err) {
reject(err);
} else if (done) {
sequentialSource.close(err2 => {
if (err2) {
reject(err2);
}
c.close();
resolve();
});
} else {
c.enqueue(chunk);
resolve();
}
});
});
}
});
stream.source = sequentialSource;
return stream;
}
function transferArrayBufferView(view) {
return structuredClone(view, { transfer: [view.buffer] });
}
self.RandomPushSource = RandomPushSource;
self.readableStreamToArray = readableStreamToArray;
self.sequentialReadableStream = sequentialReadableStream;
self.transferArrayBufferView = transferArrayBufferView;
}());