# All files / microservices/server server-rmq.ts

93.18% Statements 41/44
100% Branches 18/18
76.92% Functions 10/13
95.35% Lines 41/43

    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
    114
    115
    116
    117
    118
    1191x

    1x

    1x

    1x

    1x
    12x
    12x

    12x
    12x
    12x

    12x

    12x

    12x

    12x

    12x
    12x

    3x

    2x
    2x

    3x
    3x
    3x

    3x

    3x

    4x
    4x
    4x

    4x

    2x
    2x
    2x
    2x

    2x
    1x
    1x

    1x

    1x
    2x

    1x

    1x
    1x

     import { loadPackage } from '@nestjs/common/utils/load-package.util';
    import { Observable } from 'rxjs';
    import {
      CONNECT_EVENT,
      DISCONNECTED_RMQ_MESSAGE,
      DISCONNECT_EVENT,
      NO_PATTERN_MESSAGE,
      RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT,
      RQM_DEFAULT_PREFETCH_COUNT,
      RQM_DEFAULT_QUEUE,
      RQM_DEFAULT_QUEUE_OPTIONS,
      RQM_DEFAULT_URL,
    } from '../constants';
    import { CustomTransportStrategy, RmqOptions } from '../interfaces';
    import { MicroserviceOptions } from '../interfaces/microservice-configuration.interface';
    import { Server } from './server';

    let rqmPackage: any = {};

    export class ServerRMQ extends Server implements CustomTransportStrategy {
      private server: any = null;
      private channel: any = null;
      private readonly urls: string[];
      private readonly queue: string;
      private readonly prefetchCount: number;
      private readonly queueOptions: any;
      private readonly isGlobalPrefetchCount: boolean;

      constructor(private readonly options: MicroserviceOptions) {
        super();
        this.urls = this.getOptionsProp<RmqOptions>(this.options, 'urls') || [
          RQM_DEFAULT_URL,
        ];
        this.queue =
          this.getOptionsProp<RmqOptions>(this.options, 'queue') ||
          RQM_DEFAULT_QUEUE;
        this.prefetchCount =
          this.getOptionsProp<RmqOptions>(this.options, 'prefetchCount') ||
          RQM_DEFAULT_PREFETCH_COUNT;
        this.isGlobalPrefetchCount =
          this.getOptionsProp<RmqOptions>(this.options, 'isGlobalPrefetchCount') ||
          RQM_DEFAULT_IS_GLOBAL_PREFETCH_COUNT;
        this.queueOptions =
          this.getOptionsProp<RmqOptions>(this.options, 'queueOptions') ||
          RQM_DEFAULT_QUEUE_OPTIONS;

        loadPackage('amqplib', ServerRMQ.name);
        rqmPackage = loadPackage('amqp-connection-manager', ServerRMQ.name);
      }

      public async listen(callback: () => void): Promise<void> {
        await this.start(callback);
      }

      public close(): void {
        this.channel && this.channel.close();
        this.server && this.server.close();
      }

      public async start(callback?: () => void) {
        this.server = this.createClient();
        this.server.on(CONNECT_EVENT, _ => {
          this.channel = this.server.createChannel({
            json: false,
            setup: channel => this.setupChannel(channel, callback),
          });
        });
        this.server.on(DISCONNECT_EVENT, err => {
          this.logger.error(DISCONNECTED_RMQ_MESSAGE);
        });
      }

      public createClient<T = any>(): T {
        return rqmPackage.connect(this.urls);
      }

      public async setupChannel(channel: any, callback: Function) {
        await channel.assertQueue(this.queue, this.queueOptions);
        await channel.prefetch(this.prefetchCount, this.isGlobalPrefetchCount);
        channel.consume(this.queue, msg => this.handleMessage(msg), {
          noAck: true,
        });
        callback();
      }

      public async handleMessage(message: any): Promise<void> {
        const { content, properties } = message;
        const packet = JSON.parse(content.toString());
        const pattern = JSON.stringify(packet.pattern);
        const handler = this.getHandlerByPattern(pattern);

        if (!handler) {
          const status = 'error';
          return this.sendMessage(
            { status, err: NO_PATTERN_MESSAGE },
            properties.replyTo,
            properties.correlationId,
          );
        }
        const response$ = this.transformToObservable(
          await handler(packet.data),
        ) as Observable<any>;

        const publish = data =>
          this.sendMessage(data, properties.replyTo, properties.correlationId);

        response$ && this.send(response$, publish);
      }

      public sendMessage<T = any>(
        message: T,
        replyTo: any,
        correlationId: string,
      ): void {
        const buffer = Buffer.from(JSON.stringify(message));
        this.channel.sendToQueue(replyTo, buffer, { correlationId });
      }
    }