'use strict'; const { LatestWinsGate } = require('generalFunctions'); // Thin wrapper around LatestWinsGate for the MGC demand path. Replaces // the original `_dispatchInFlight` + `_delayedCall` pair in // specificClass.handleInput: a new demand arriving while a dispatch is // in flight overwrites any pending one, so the latest value always wins // and intermediates are dropped silently. class DemandDispatcher { constructor(ctx = {}, runFn) { if (typeof runFn !== 'function') { throw new TypeError('DemandDispatcher requires a runFn'); } this.ctx = ctx; this.logger = ctx.logger || null; this._runFn = runFn; this._gate = new LatestWinsGate( async (demand) => this._runFn(demand, this.ctx), { logger: this.logger }, ); } fire(demand) { this._gate.fire(demand); } // Returns a promise that resolves when THIS demand's dispatch settles. // If superseded by a later fireAndWait while parked, the promise // resolves with the LatestWinsGate SUPERSEDED sentinel // ({ superseded: true }) — callers can branch on it without try/catch. fireAndWait(demand) { return this._gate.fireAndWait(demand); } drain() { return this._gate.drain(); } // Cancels any parked pending value so it cannot run. The currently // in-flight dispatch (if any) still runs to completion. A parked // fireAndWait promise resolves with the SUPERSEDED sentinel. cancelPending() { if (this._gate._pending) this._gate._supersedePending(); } get inFlight() { return this._gate.size > 0; } } module.exports = DemandDispatcher;