All files / microservices/client client-nats.ts

95.12% Statements 39/41
87.5% Branches 14/16
90% Functions 9/10
95% Lines 38/40
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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 1071x 1x 1x 1x       1x 1x   1x   1x 2x         2x 2x 2x   2x       1x 1x 1x       9x 5x   4x 4x   4x     4x                         5x   1x               5x 3x 1x   2x 2x 1x           1x                     3x 3x 2x   2x       2x         2x   1x        
import { Logger } from '@nestjs/common/services/logger.service';
import { loadPackage } from '@nestjs/common/utils/load-package.util';
import { share } from 'rxjs/operators';
import { ERROR_EVENT, NATS_DEFAULT_URL } from '../constants';
import { Client } from '../external/nats-client.interface';
import { NatsOptions, PacketId, ReadPacket, WritePacket } from '../interfaces';
import { ClientOptions } from '../interfaces/client-metadata.interface';
import { ClientProxy } from './client-proxy';
import { CONN_ERR } from './constants';
 
let natsPackage: any = {};
 
export class ClientNats extends ClientProxy {
  protected readonly logger = new Logger(ClientProxy.name);
  protected readonly url: string;
  protected natsClient: Client;
  protected connection: Promise<any>;
 
  constructor(protected readonly options: ClientOptions['options']) {
    super();
    this.url =
      this.getOptionsProp<NatsOptions>(this.options, 'url') || NATS_DEFAULT_URL;
    natsPackage = loadPackage('nats', ClientNats.name);
  }
 
  public close() {
    this.natsClient && this.natsClient.close();
    this.natsClient = null;
    this.connection = null;
  }
 
  public async connect(): Promise<any> {
    if (this.natsClient) {
      return this.connection;
    }
    this.natsClient = this.createClient();
    this.handleError(this.natsClient);
 
    this.connection = await this.connect$(this.natsClient)
      .pipe(share())
      .toPromise();
    return this.connection;
  }
 
  public createClient(): Client {
    const options: any = this.options || ({} as NatsOptions);
    return natsPackage.connect({
      ...options,
      url: this.url,
      json: true,
    });
  }
 
  public handleError(client: Client) {
    client.addListener(
      ERROR_EVENT,
      err => err.code !== CONN_ERR && this.logger.error(err),
    );
  }
 
  public createSubscriptionHandler(
    packet: ReadPacket & PacketId,
    callback: (packet: WritePacket) => any,
  ): Function {
    return (message: WritePacket & PacketId) => {
      if (message.id !== packet.id) {
        return undefined;
      }
      const { err, response, isDisposed } = message;
      if (isDisposed || err) {
        return callback({
          err,
          response: null,
          isDisposed: true,
        });
      }
      callback({
        err,
        response,
      });
    };
  }
 
  protected publish(
    partialPacket: ReadPacket,
    callback: (packet: WritePacket) => any,
  ): Function {
    try {
      const packet = this.assignPacketId(partialPacket);
      const channel = this.normalizePattern(partialPacket.pattern);
 
      const subscriptionHandler = this.createSubscriptionHandler(
        packet,
        callback,
      );
      const subscriptionId = this.natsClient.request(
        channel,
        packet as any,
        subscriptionHandler,
      );
      return () => this.natsClient.unsubscribe(subscriptionId);
    } catch (err) {
      callback({ err });
    }
  }
}