UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

120 lines 4.32 kB
import { LinkedList } from "./array.js"; import { fromThreadBoundaryError, toThreadBoundaryError } from "./error.js"; export var IteratorEventType; (function (IteratorEventType) { IteratorEventType["next"] = "iterator.next"; IteratorEventType["done"] = "iterator.done"; IteratorEventType["error"] = "iterator.error"; })(IteratorEventType || (IteratorEventType = {})); export class AsyncIterableBridgeCaller { constructor(events) { this.events = events; this.nextRequestId = 0; // TODO: Consider expiring the requests after no reply for long enough, t this.pending = new Map(); events.onResponse(this.onResponse.bind(this)); } get pendingCount() { return this.pending.size; } getAsyncIterable(callArgs) { const self = this; return { [Symbol.asyncIterator]() { const id = self.nextRequestId++; const req = { items: new LinkedList(), done: false, error: null, onNext: null, }; self.pending.set(id, req); self.events.emitRequest({ callArgs, id, }); return { async next() { while (true) { const item = req.items.shift(); if (item !== null) { return { value: item, done: false }; } if (req.error) { throw req.error; } if (req.done) { // Is it correct to return undefined on done: true? return { value: undefined, done: true }; } await new Promise((resolve) => { req.onNext = resolve; }); } }, async return() { // This will be reached if the consumer called 'break' or 'return' early in the loop. self.pending.delete(id); return { value: undefined, done: true }; }, }; }, }; } onResponse(data) { const req = this.pending.get(data.id); if (!req) { // TODO: Log or track, can happen if consumer returns source early return; } switch (data.type) { case IteratorEventType.done: // What if it's already done? req.done = true; // Do not expect more responses this.pending.delete(data.id); break; case IteratorEventType.error: // What if there's already an error? req.error = fromThreadBoundaryError(data.error); // Do not expect more responses this.pending.delete(data.id); break; case IteratorEventType.next: // Should check that's it's already done or error? req.items.push(data.item); break; } req.onNext?.(); } } export class AsyncIterableBridgeHandler { constructor(events, handler) { this.events = events; this.handler = handler; events.onRequest(this.onRequest.bind(this)); } async onRequest(data) { try { for await (const item of this.handler(data.callArgs)) { this.events.emitResponse({ type: IteratorEventType.next, id: data.id, item, }); } this.events.emitResponse({ type: IteratorEventType.done, id: data.id, }); } catch (e) { this.events.emitResponse({ type: IteratorEventType.error, id: data.id, error: toThreadBoundaryError(e), }); } } } //# sourceMappingURL=asyncIterableToEvents.js.map