function createSentinel()

in packages/dubbo-node/src/node-universal-client.ts [470:529]


function createSentinel(signal?: AbortSignal): Sentinel {
  let res: (() => void) | undefined;
  let rej: ((reason: ConnectError | unknown) => void) | undefined;
  let resolved = false;
  let rejected = false;
  const p = new Promise<void>((resolve, reject) => {
    res = resolve;
    rej = reject;
  });
  const c: Pick<
    Sentinel,
    "resolve" | "isResolved" | "reject" | "isRejected" | "race"
  > = {
    resolve(): void {
      if (!resolved && !rejected) {
        resolved = true;
        res?.();
      }
    },
    isResolved() {
      return resolved;
    },
    reject(reason): void {
      if (!resolved && !rejected) {
        rejected = true;
        rej?.(connectErrorFromNodeReason(reason));
      }
    },
    isRejected() {
      return rejected;
    },
    async race<T>(promise: PromiseLike<T>): Promise<Awaited<T>> {
      const r = await Promise.race([promise, p]);
      if (r === undefined && resolved) {
        throw new ConnectError("sentinel completed early", Code.Internal);
      }
      return r as Awaited<T>;
    },
  };
  const s = Object.assign(p, c);

  function onSignalAbort(this: AbortSignal) {
    c.reject(getAbortSignalReason(this));
  }

  if (signal) {
    if (signal.aborted) {
      c.reject(getAbortSignalReason(signal));
    } else {
      signal.addEventListener("abort", onSignalAbort);
    }
    p.finally(() => signal.removeEventListener("abort", onSignalAbort)).catch(
      () => {
        // We intentionally swallow sentinel rejection - errors must
        // propagate through the request or response iterables.
      }
    );
  }
  return s;
}