AkashBabu/supervised-emitter

View on GitHub
src/interfaces.ts

Summary

Maintainability
A
0 mins
Test Coverage
import {DLL} from '@akashbabu/node-dll';
import LFUCache from '@akashbabu/lfu-cache';

export type IHandler = (ctx: IContext, ...args: any[]) => any | Promise<any>;

/**
 * Context object that will be passed as the second argument
 * to subscribers and first argument to middlewares
 */
export interface IContext {
  /**
   * Data that was published.
   * Since data is piped through the middleware
   * pipeline and then through all subscription
   * pipeline, this might NOT be the same as
   * published.
   */
  data: any;

  /**
   * Published event.
   * This information can be used in middlewares to
   * maintain a stack of event that were published in
   * the system and the same can be used to reproduce
   * a bug.
   */
  pubEvent: string;

  /**
   * All subEvents that match the pubEvent.
   * Note that even if multiple pipelines are hooked
   * to the same subEvent, this Array would include it
   * only once. So NO duplicate event will be found in
   * subEvents.
   */
  subEvents: string[];

  /**
   * This promise will be resolved when the pipeline
   * has completed execution. This can be very useful
   * in situations wherein the user wants to execute some action
   * when this pipeline has been completed, irrespective of
   * whether it is stopped in between or has completed the pipeline.
   * In fact, same technique was used to create subscribeOnce
   * feature as well.
   *
   * Note: User MUST NOT await on this promise, instead `then`
   * must be used because if awaited, it would wait for Infinite time
   * as it results in a circular dependent promise.
   */
  pipelinePromise?: Promise<any>;

  /**
   * Any other properties that the middleware/subscription
   * pipeline desires to add to the context. This technique
   * can be used to create methods like printEventTrace, onEnd etc
   */
  [newProp: string]: any;
}

/** Function signature of middlewares */
export type IMiddleware = (ctx: IContext) => Promise<any>|any;

/** Options to be passed to the constructor */
export interface IOptions {
  debug?: boolean;
  lfu?: object;
  publishConcurrency?: number;
  lifeCycleEvents?: boolean;
}

/**
 * @hidden
 *
 * Options interface for internal usage.
 * This was created, since the original IOptions object
 * has a couple of options property which causes `may be undefined`
 * error during usage even after assigning default param to it.
 * Hence this interface solved the problem
 */
export interface IOptionsInt {
  debug: boolean;
  lfu: object;
  publishConcurrency: number;
  lifeCycleEvents: boolean;
}

/** SupervisedEmitter's interface */
export interface ISupervisedEmitter {
  /** Subscribes to an event */
  subscribe(event: string, ...handlers: IHandler[]): ISubscription;

  /** Subscribes to an event only once */
  subscribeOnce(event: string, ...handlers: IHandler[]): Promise<any>;

  /** Waits untill the required event is fired */
  waitTill(event: string): Promise<any>;

  /** Publishes data on the given pubEvent */
  publish(pubEvent: string, data: any): Promise<any>;

  /** Returns a Closure function that adds scope to an event */
  getScope(): IGetScope;

  /** This strips the scope part in the given event */
  unScope(event: string): string;
}

/**
 * `.subscribe()` method's interface. Since this interface
 * return [[ISubscription]] on subscribe|subscribeOnce, you may
 * chain as many subscriptions as needed and all the chained
 * subscription can be unsubscribed by running unsubscription
 * just once on the final subscription returned.
 *
 * **Example**
 * ```TS
 * const subscription = SE.subscribe('foo/bar', () => {})
 *                        .subscribe('hello/world', () => {});
 *
 * subscription.unsubscribe();
 * ```
 */
export interface ISubscription {
  unsubscribe(): void; // for unsubscribing from the event
  subscribe(event: string, ...handlers: IHandler[]): ISubscription; // for chaining multiple subscriptions
}

/**
 * @hidden
 */
export interface IState {
  // map of event vs pipelines (DLL)
  subscribers: Map<string, DLL<ISubPipeline>>;

  // list of pattern events
  patternEvents: string[];

  // cache for maintaining pubEvents vs matching subEvents
  subEventsCache: LFUCache<Map<string, boolean>>;

  // use to generate a new scope part
  scopeId: number;
}

/**
 * Closure function that can add scope
 * to the provide event
 *
 * @param event Event
 */
export type IGetScope = (event: string) => string;

export interface ISubPipeline {
  pipeline: IHandler;
}