@atproto/common-web
Version:
Shared web-platform-friendly code for atproto libraries
209 lines • 6.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsyncBufferFullError = exports.AsyncBuffer = exports.allComplete = exports.createDeferrables = exports.createDeferrable = exports.readFromGenerator = void 0;
exports.allFulfilled = allFulfilled;
exports.handleAllSettledErrors = handleAllSettledErrors;
exports.isRejectedResult = isRejectedResult;
exports.isFulfilledResult = isFulfilledResult;
const util_1 = require("./util");
// reads values from a generator into a list
// breaks when isDone signals `true` AND `waitFor` completes OR when a max length is reached
// NOTE: does not signal generator to close. it *will* continue to produce values
const readFromGenerator = async (gen, isDone, waitFor = Promise.resolve(), maxLength = Number.MAX_SAFE_INTEGER) => {
const evts = [];
let bail;
let hasBroke = false;
const awaitDone = async () => {
if (await isDone(evts.at(-1))) {
return true;
}
const bailable = (0, util_1.bailableWait)(20);
await bailable.wait();
bail = bailable.bail;
if (hasBroke)
return false;
return await awaitDone();
};
const breakOn = new Promise((resolve) => {
waitFor.then(() => {
awaitDone().then(() => resolve());
});
});
try {
while (evts.length < maxLength) {
const maybeEvt = await Promise.race([gen.next(), breakOn]);
if (!maybeEvt)
break;
const evt = maybeEvt;
if (evt.done)
break;
evts.push(evt.value);
}
}
finally {
hasBroke = true;
bail && bail();
}
return evts;
};
exports.readFromGenerator = readFromGenerator;
const createDeferrable = () => {
let resolve;
const promise = new Promise((res) => {
resolve = () => res();
});
return { resolve, complete: promise };
};
exports.createDeferrable = createDeferrable;
const createDeferrables = (count) => {
const list = [];
for (let i = 0; i < count; i++) {
list.push((0, exports.createDeferrable)());
}
return list;
};
exports.createDeferrables = createDeferrables;
const allComplete = async (deferrables) => {
await Promise.all(deferrables.map((d) => d.complete));
};
exports.allComplete = allComplete;
class AsyncBuffer {
constructor(maxSize) {
Object.defineProperty(this, "maxSize", {
enumerable: true,
configurable: true,
writable: true,
value: maxSize
});
Object.defineProperty(this, "buffer", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "promise", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "resolve", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "closed", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "toThrow", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
// Initializing to satisfy types/build, immediately reset by resetPromise()
this.promise = Promise.resolve();
this.resolve = () => null;
this.resetPromise();
}
get curr() {
return this.buffer;
}
get size() {
return this.buffer.length;
}
get isClosed() {
return this.closed;
}
resetPromise() {
this.promise = new Promise((r) => (this.resolve = r));
}
push(item) {
this.buffer.push(item);
this.resolve();
}
pushMany(items) {
items.forEach((i) => this.buffer.push(i));
this.resolve();
}
async *events() {
while (true) {
if (this.closed && this.buffer.length === 0) {
if (this.toThrow) {
throw this.toThrow;
}
else {
return;
}
}
await this.promise;
if (this.toThrow) {
throw this.toThrow;
}
if (this.maxSize && this.size > this.maxSize) {
throw new AsyncBufferFullError(this.maxSize);
}
const [first, ...rest] = this.buffer;
if (first) {
this.buffer = rest;
yield first;
}
else {
this.resetPromise();
}
}
}
throw(err) {
this.toThrow = err;
this.closed = true;
this.resolve();
}
close() {
this.closed = true;
this.resolve();
}
}
exports.AsyncBuffer = AsyncBuffer;
class AsyncBufferFullError extends Error {
constructor(maxSize) {
super(`ReachedMaxBufferSize: ${maxSize}`);
}
}
exports.AsyncBufferFullError = AsyncBufferFullError;
function allFulfilled(promises) {
return Promise.allSettled(promises).then(handleAllSettledErrors);
}
function handleAllSettledErrors(results) {
const errors = results.filter(isRejectedResult).map(extractReason);
if (errors.length === 0) {
// No need to filter here, it is safe to assume that all promises are fulfilled
return results.map(extractValue);
}
if (errors.length === 1) {
throw errors[0];
}
throw new AggregateError(errors, `Multiple errors: ${errors.map(stringifyReason).join('\n')}`);
}
function isRejectedResult(result) {
return result.status === 'rejected';
}
function extractReason(result) {
return result.reason;
}
function isFulfilledResult(result) {
return result.status === 'fulfilled';
}
function extractValue(result) {
return result.value;
}
function stringifyReason(reason) {
if (reason instanceof Error) {
return reason.message;
}
return String(reason);
}
//# sourceMappingURL=async.js.map