UNPKG

@opra/nestjs

Version:
117 lines (116 loc) 5.68 kB
import { __decorate, __metadata } from "tslib"; import { Controller, Injectable } from '@nestjs/common'; import { createContextId, ModulesContainer, REQUEST } from '@nestjs/core'; import { ExternalContextCreator, } from '@nestjs/core/helpers/external-context-creator.js'; import { Injector } from '@nestjs/core/injector/injector.js'; import { InternalCoreModule } from '@nestjs/core/injector/internal-core-module/index.js'; import { REQUEST_CONTEXT_ID } from '@nestjs/core/router/request/request-constants.js'; import { PARAM_ARGS_METADATA } from '@nestjs/microservices/constants.js'; import { RPC_CONTROLLER_METADATA } from '@opra/common'; import { OpraNestUtils } from './opra-nest-utils.js'; import { RpcParamsFactory } from './rpc-params.factory.js'; let RpcControllerFactory = class RpcControllerFactory { constructor(modulesContainer, externalContextCreator) { this.modulesContainer = modulesContainer; this.externalContextCreator = externalContextCreator; this.paramsFactory = new RpcParamsFactory(); this.injector = new Injector(); } wrapControllers() { const out = []; for (const { module, wrapper } of this.exploreControllers()) { const instance = wrapper.instance; const sourceClass = instance.constructor; const metadata = Reflect.getMetadata(RPC_CONTROLLER_METADATA, sourceClass); const isRequestScoped = !wrapper.isDependencyTreeStatic(); /** Create a new controller class */ const newClass = { [sourceClass.name]: class extends sourceClass { }, }[sourceClass.name]; /** Copy metadata keys from source class to new one */ OpraNestUtils.copyDecoratorMetadata(newClass, sourceClass); Controller()(newClass); out.push(newClass); if (metadata.operations) { for (const operationName of Object.keys(metadata.operations)) { // const orgFn: Function = sourceClass.prototype[operationName]; newClass.prototype[operationName] = this._createContextCallback(instance, wrapper, module, operationName, isRequestScoped, 'rpc'); Reflect.defineMetadata(PARAM_ARGS_METADATA, [REQUEST], instance.constructor, operationName); } } } return out; } _createContextCallback(instance, wrapper, moduleRef, methodName, isRequestScoped, contextType, options) { const paramsFactory = this.paramsFactory; if (isRequestScoped) { return async (opraContext) => { const contextId = createContextId(); Object.defineProperty(opraContext, REQUEST_CONTEXT_ID, { value: contextId, enumerable: false, configurable: false, writable: false, }); this.registerContextProvider(opraContext, contextId); const contextInstance = await this.injector.loadPerContext(instance, moduleRef, moduleRef.providers, contextId); const contextCallback = this.externalContextCreator.create(contextInstance, contextInstance[methodName], methodName, PARAM_ARGS_METADATA, paramsFactory, contextId, wrapper.id, options, opraContext.protocol); return contextCallback(opraContext); }; } return this.externalContextCreator.create(instance, instance[methodName], methodName, PARAM_ARGS_METADATA, paramsFactory, undefined, undefined, options, contextType); } registerContextProvider(request, contextId) { if (!this._coreModuleRef) { const coreModuleArray = [...this.modulesContainer.entries()] .filter( // eslint-disable-next-line @typescript-eslint/no-unused-vars ([_, { metatype }]) => metatype && metatype.name === InternalCoreModule.name) // eslint-disable-next-line @typescript-eslint/no-unused-vars .map(([_, value]) => value); this._coreModuleRef = coreModuleArray[0]; } if (!this._coreModuleRef) { return; } const wrapper = this._coreModuleRef.getProviderByKey(REQUEST); wrapper.setInstanceByContextId(contextId, { instance: request, isResolved: true, }); } exploreControllers() { const scannedModules = new Set(); const controllers = new Set(); const scanModule = (module) => { if (scannedModules.has(module)) return; scannedModules.add(module); for (const mm of module.imports.values()) { scanModule(mm); } for (const wrapper of module.controllers.values()) { if (wrapper.instance && typeof wrapper.instance === 'object' && wrapper.instance.constructor && Reflect.getMetadata(RPC_CONTROLLER_METADATA, wrapper.instance.constructor) && !controllers.has(wrapper)) { controllers.add({ module, wrapper }); } if (wrapper.host) scanModule(wrapper.host); } }; for (const module of this.modulesContainer.values()) { scanModule(module); } return Array.from(controllers); } }; RpcControllerFactory = __decorate([ Injectable(), __metadata("design:paramtypes", [ModulesContainer, ExternalContextCreator]) ], RpcControllerFactory); export { RpcControllerFactory };