Verkehrsministerium/kraftfahrstrasse

View on GitHub
src/util/map.ts

Summary

Maintainability
A
3 hrs
Test Coverage
import { Deferred } from './deferred';

import { EWampMessageID, WampID } from '../types/messages/MessageTypes';
import { WampMessage } from '../types/Protocol';

export class PendingMap<TSucMsg extends WampMessage> {
  private pendings = new Map<WampID, Deferred<TSucMsg>>();
  private closed = false;

  constructor(
    private initMsg: EWampMessageID,
    private successMsg: EWampMessageID,
    private emptyRequest?: (msg: TSucMsg) => [boolean, string],
  ) { }

  public Remove(pendingId: WampID, err?: any): void {
    const p = this.pendings.get(pendingId);
    if (!p) {
      return;
    }
    this.pendings.delete(pendingId);
    p.reject(err);
  }

  public Close(): void {
    this.closed = true;
    for (const pending of this.pendings) {
      pending[1].reject('closing');
    }
    this.pendings.clear();
  }

  public PutAndResolve(id: WampID): Promise<TSucMsg> {
    const deferred = new Deferred<TSucMsg>();
    this.pendings.set(id, deferred);
    return deferred.promise;
  }

  public Handle(msg: WampMessage): [boolean, boolean, string] {
    if (this.closed) {
      return [false, true, ''];
    }
    if (msg[0] === this.successMsg) {
      const requestID = msg[1];
      if (requestID === 0 && !!this.emptyRequest) {
        const [success, error] = this.emptyRequest(msg as TSucMsg);
        return [true, success, error];
      }
      const pendingRequest = this.getAndDelete(requestID as WampID);
      if (!pendingRequest) {
        return [true, false, 'unexpected ' + EWampMessageID[this.successMsg]];
      }
      pendingRequest.resolve(msg as TSucMsg);
      return [true, true, ''];
    }

    if (msg[0] === EWampMessageID.ERROR && msg[1] === this.initMsg) {
      const requestID = msg[2];
      const pendingRequest = this.getAndDelete(requestID);
      if (!pendingRequest) {
        return [true, false, 'unexpected ' + EWampMessageID[this.initMsg] + ' ERROR'];
      }
      pendingRequest.reject(msg[4]);
      return [true, true, ''];
    }
    return [false, true, ''];
  }

  private getAndDelete(id: WampID): Deferred<TSucMsg> | null {
    const val = this.pendings.get(id);
    this.pendings.delete(id);
    return val || null;
  }
}