# All files / microservices/client client-proxy.ts

96.67% Statements 29/30
93.33% Branches 14/15
92.31% Functions 12/13
96.43% Lines 27/28

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    931x
    1x
    1x

    1x
    1x
    1x

    1x

    51x

    5x
    1x

    4x

    2x
    2x
    2x

    4x
    3x
    1x
    2x
    1x

    1x

    5x
    5x

    4x

    4x
    4x

    124x

    11x

     import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util';
    import { isNil, isString } from '@nestjs/common/utils/shared.utils';
    import {
      defer,
      fromEvent,
      merge,
      Observable,
      Observer,
      throwError as _throw,
    } from 'rxjs';
    import { map, mergeMap, take } from 'rxjs/operators';
    import { CONNECT_EVENT, ERROR_EVENT } from '../constants';
    import { InvalidMessageException } from '../exceptions/errors/invalid-message.exception';
    import {
      ClientOptions,
      PacketId,
      ReadPacket,
      WritePacket,
    } from '../interfaces';

    export abstract class ClientProxy {
      public abstract connect(): Promise<any>;
      public abstract close(): any;
      protected routingMap = new Map<string, Function>();

      public send<TResult = any, TInput = any>(
        pattern: any,
        data: TInput,
      ): Observable<TResult> {
        if (isNil(pattern) || isNil(data)) {
          return _throw(new InvalidMessageException());
        }
        return defer(async () => this.connect()).pipe(
          mergeMap(
            () =>
              new Observable((observer: Observer<TResult>) => {
                const callback = this.createObserver(observer);
                return this.publish({ pattern, data }, callback);
              }),
          ),
        );
      }

      protected abstract publish(
        packet: ReadPacket,
        callback: (packet: WritePacket) => void,
      ): Function | void;

      protected createObserver<T>(
        observer: Observer<T>,
      ): (packet: WritePacket) => void {
        return ({ err, response, isDisposed }: WritePacket) => {
          if (err) {
            return observer.error(err);
          } else if (isDisposed) {
            return observer.complete();
          }
          observer.next(response);
        };
      }

      protected assignPacketId(packet: ReadPacket): ReadPacket & PacketId {
        const id = randomStringGenerator();
        return Object.assign(packet, { id });
      }

      protected connect$(
        instance: any,
        errorEvent = ERROR_EVENT,
        connectEvent = CONNECT_EVENT,
      ): Observable<any> {
        const error$ = fromEvent(instance, errorEvent).pipe(
          map(err => {
            throw err;
          }),
        );
        const connect$ = fromEvent(instance, connectEvent);
        return merge(error$, connect$).pipe(take(1));
      }

      protected getOptionsProp<T extends { options? }>(
        obj: ClientOptions['options'],
        prop: keyof T['options'],
        defaultValue = undefined,
      ) {
        return obj ? obj[prop as string] : defaultValue;
      }

      protected normalizePattern<T = any>(pattern: T): string {
        return isString(pattern) ? pattern : JSON.stringify(pattern);
      }
    }