All files / microservices/server server-nats.ts

89.74% Statements 35/39
75% Branches 9/12
87.5% Functions 14/16
91.67% Lines 33/36
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 107 108 109 110 111 112 113  1x                         1x   1x   1x       11x 11x 11x     11x       2x 2x 2x       2x 2x       3x 3x 1x             1x         3x 3x       1x 1x                         3x 1x                 2x 2x   2x 1x   1x 1x     1x       3x 1x                 2x      
import { Observable } from 'rxjs';
import {
  CONNECT_EVENT,
  ERROR_EVENT,
  NATS_DEFAULT_URL,
  NO_PATTERN_MESSAGE,
} from '../constants';
import { Client } from '../external/nats-client.interface';
import { CustomTransportStrategy, PacketId } from '../interfaces';
import {
  MicroserviceOptions,
  NatsOptions,
} from '../interfaces/microservice-configuration.interface';
import { ReadPacket } from '../interfaces/packet.interface';
import { Server } from './server';
 
let natsPackage: any = {};
 
export class ServerNats extends Server implements CustomTransportStrategy {
  private readonly url: string;
  private natsClient: Client;
 
  constructor(private readonly options: MicroserviceOptions['options']) {
    super();
    this.url =
      this.getOptionsProp<NatsOptions>(this.options, 'url') || NATS_DEFAULT_URL;
 
    natsPackage = this.loadPackage('nats', ServerNats.name);
  }
 
  public listen(callback: () => void) {
    this.natsClient = this.createNatsClient();
    this.handleError(this.natsClient);
    this.start(callback);
  }
 
  public start(callback?: () => void) {
    this.bindEvents(this.natsClient);
    this.natsClient.on(CONNECT_EVENT, callback);
  }
 
  public bindEvents(client: Client) {
    const queue = this.getOptionsProp<NatsOptions>(this.options, 'queue');
    const subscribe = (channel: string) => {
      Iif (queue) {
        return client.subscribe(
          channel,
          { queue },
          this.getMessageHandler(channel, client).bind(this),
        );
      }
      client.subscribe(
        channel,
        this.getMessageHandler(channel, client).bind(this),
      );
    };
    const registeredPatterns = Object.keys(this.messageHandlers);
    registeredPatterns.forEach(channel => subscribe(channel));
  }
 
  public close() {
    this.natsClient && this.natsClient.close();
    this.natsClient = null;
  }
 
  public createNatsClient(): Client {
    const options = this.options || ({} as NatsOptions);
    return natsPackage.connect({
      ...options,
      url: this.url,
      json: true,
    });
  }
 
  public getMessageHandler(channel: string, client: Client) {
    return async (buffer, replyTo: string) =>
      this.handleMessage(channel, buffer, client, replyTo);
  }
 
  public async handleMessage(
    channel: string,
    message: ReadPacket & PacketId,
    client: Client,
    replyTo: string,
  ) {
    const publish = this.getPublisher(client, replyTo, message.id);
    const status = 'error';
 
    if (!this.messageHandlers[channel]) {
      return publish({ id: message.id, status, err: NO_PATTERN_MESSAGE });
    }
    const handler = this.messageHandlers[channel];
    const response$ = this.transformToObservable(
      await handler(message.data),
    ) as Observable<any>;
    response$ && this.send(response$, publish);
  }
 
  public getPublisher(publisher: Client, replyTo: string, id: string) {
    return response =>
      publisher.publish(
        replyTo,
        Object.assign(response, {
          id,
        }),
      );
  }
 
  public handleError(stream) {
    stream.on(ERROR_EVENT, err => this.logger.error(err));
  }
}