# All files / microservices/context rpc-context-creator.ts

100% Statements 37/37
100% Branches 10/10
100% Functions 12/12
100% Lines 33/33

    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
    1001x

    1x

    1x

    1x

    10x
    10x
    10x
    10x
    10x
    10x
    10x
    10x

    6x

    6x
    6x
    6x
    6x

    6x
    6x
    3x
    3x

    3x

    6x
    3x

    3x

    9x

    8x
    8x

    7x
    2x

    2x
    1x

    7x

     import { PARAMTYPES_METADATA } from '@nestjs/common/constants';
    import { Controller } from '@nestjs/common/interfaces';
    import { FORBIDDEN_MESSAGE } from '@nestjs/core/guards/constants';
    import { GuardsConsumer } from '@nestjs/core/guards/guards-consumer';
    import { GuardsContextCreator } from '@nestjs/core/guards/guards-context-creator';
    import { InterceptorsConsumer } from '@nestjs/core/interceptors/interceptors-consumer';
    import { InterceptorsContextCreator } from '@nestjs/core/interceptors/interceptors-context-creator';
    import { PipesConsumer } from '@nestjs/core/pipes/pipes-consumer';
    import { PipesContextCreator } from '@nestjs/core/pipes/pipes-context-creator';
    import { Observable } from 'rxjs';
    import { RpcException } from '..';
    import { ExceptionFiltersContext } from './exception-filters-context';
    import { RpcProxy } from './rpc-proxy';

    export class RpcContextCreator {
      constructor(
        private readonly rpcProxy: RpcProxy,
        private readonly exceptionFiltersContext: ExceptionFiltersContext,
        private readonly pipesCreator: PipesContextCreator,
        private readonly pipesConsumer: PipesConsumer,
        private readonly guardsContextCreator: GuardsContextCreator,
        private readonly guardsConsumer: GuardsConsumer,
        private readonly interceptorsContextCreator: InterceptorsContextCreator,
        private readonly interceptorsConsumer: InterceptorsConsumer,
      ) {}

      public create(
        instance: Controller,
        callback: (data) => Observable<any>,
        module,
      ): (...args) => Promise<Observable<any>> {
        const exceptionHandler = this.exceptionFiltersContext.create(
          instance,
          callback,
          module,
        );
        const pipes = this.pipesCreator.create(instance, callback, module);
        const guards = this.guardsContextCreator.create(instance, callback, module);
        const metatype = this.getDataMetatype(instance, callback);
        const interceptors = this.interceptorsContextCreator.create(
          instance,
          callback,
          module,
        );
        const fnCanActivate = this.createGuardsFn(guards, instance, callback);
        const handler = (args: any[]) => async () => {
          const [data, ...params] = args;
          const result = await this.pipesConsumer.applyPipes(
            data,
            { metatype },
            pipes,
          );
          return callback.call(instance, result, ...params);
        };

        return this.rpcProxy.create(async (...args) => {
          fnCanActivate && (await fnCanActivate(args));

          return this.interceptorsConsumer.intercept(
            interceptors,
            args,
            instance,
            callback,
            handler(args),
          );
        }, exceptionHandler);
      }

      public reflectCallbackParamtypes(
        instance: Controller,
        callback: (...args) => any,
      ): any[] {
        return Reflect.getMetadata(PARAMTYPES_METADATA, instance, callback.name);
      }

      public getDataMetatype(instance, callback) {
        const paramtypes = this.reflectCallbackParamtypes(instance, callback);
        return paramtypes && paramtypes.length ? paramtypes[0] : null;
      }

      public createGuardsFn(
        guards: any[],
        instance: Controller,
        callback: (...args) => any,
      ): Function | null {
        const canActivateFn = async (args: any[]) => {
          const canActivate = await this.guardsConsumer.tryActivate(
            guards,
            args,
            instance,
            callback,
          );
          if (!canActivate) {
            throw new RpcException(FORBIDDEN_MESSAGE);
          }
        };
        return guards.length ? canActivateFn : null;
      }
    }