UNPKG

@nestjs/core

Version:

Nest - modern, fast, powerful node.js web framework (@core)

223 lines (222 loc) 8.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const common_1 = require("@nestjs/common"); const shared_utils_1 = require("@nestjs/common/utils/shared.utils"); const constants_1 = require("./constants"); const unknown_element_exception_1 = require("./errors/exceptions/unknown-element.exception"); const unknown_module_exception_1 = require("./errors/exceptions/unknown-module.exception"); const helpers_1 = require("./helpers"); const hooks_1 = require("./hooks"); const container_scanner_1 = require("./injector/container-scanner"); const injector_1 = require("./injector/injector"); const iterare_1 = require("iterare"); /** * @publicApi */ class NestApplicationContext { constructor(container, scope = new Array(), contextModule = null) { this.container = container; this.scope = scope; this.contextModule = contextModule; this.isInitialized = false; this.injector = new injector_1.Injector(); this.activeShutdownSignals = new Array(); this.containerScanner = new container_scanner_1.ContainerScanner(container); } selectContextModule() { const modules = this.container.getModules().values(); this.contextModule = modules.next().value; } select(moduleType) { const modules = this.container.getModules(); const moduleMetatype = this.contextModule.metatype; const scope = this.scope.concat(moduleMetatype); const moduleTokenFactory = this.container.getModuleTokenFactory(); const token = moduleTokenFactory.create(moduleType); const selectedModule = modules.get(token); if (!selectedModule) { throw new unknown_module_exception_1.UnknownModuleException(); } return new NestApplicationContext(this.container, scope, selectedModule); } get(typeOrToken, options = { strict: false }) { if (!(options && options.strict)) { return this.find(typeOrToken); } return this.findInstanceByToken(typeOrToken, this.contextModule); } resolve(typeOrToken, contextId = helpers_1.createContextId(), options = { strict: false }) { return this.resolvePerContext(typeOrToken, this.contextModule, contextId, options); } /** * Initalizes the Nest application. * Calls the Nest lifecycle events. * * @returns {Promise<this>} The NestApplicationContext instance as Promise */ async init() { if (this.isInitialized) { return this; } await this.callInitHook(); await this.callBootstrapHook(); this.isInitialized = true; return this; } async close() { await this.callDestroyHook(); await this.callBeforeShutdownHook(); await this.dispose(); await this.callShutdownHook(); await this.unsubscribeFromProcessSignals(); } useLogger(logger) { common_1.Logger.overrideLogger(logger); } /** * Enables the usage of shutdown hooks. Will call the * `onApplicationShutdown` function of a provider if the * process receives a shutdown signal. * * @param {ShutdownSignal[]} [signals=[]] The system signals it should listen to * * @returns {this} The Nest application context instance */ enableShutdownHooks(signals = []) { if (shared_utils_1.isEmpty(signals)) { signals = Object.keys(common_1.ShutdownSignal).map((key) => common_1.ShutdownSignal[key]); } else { // given signals array should be unique because // process shouldn't listen to the same signal more than once. signals = Array.from(new Set(signals)); } signals = iterare_1.iterate(signals) .map((signal) => signal .toString() .toUpperCase() .trim()) // filter out the signals which is already listening to .filter(signal => !this.activeShutdownSignals.includes(signal)) .toArray(); this.listenToShutdownSignals(signals); return this; } async dispose() { // Nest application context has no server // to dispose, therefore just call a noop return Promise.resolve(); } /** * Listens to shutdown signals by listening to * process events * * @param {string[]} signals The system signals it should listen to */ listenToShutdownSignals(signals) { const cleanup = async (signal) => { try { signals.forEach(sig => process.removeListener(sig, cleanup)); await this.callDestroyHook(); await this.callBeforeShutdownHook(signal); await this.dispose(); await this.callShutdownHook(signal); process.kill(process.pid, signal); } catch (err) { common_1.Logger.error(constants_1.MESSAGES.ERROR_DURING_SHUTDOWN, err.stack, NestApplicationContext.name); process.exit(1); } }; this.shutdownCleanupRef = cleanup; signals.forEach((signal) => { this.activeShutdownSignals.push(signal); process.on(signal, cleanup); }); } /** * Unsubscribes from shutdown signals (process events) */ unsubscribeFromProcessSignals() { if (!this.shutdownCleanupRef) { return; } this.activeShutdownSignals.forEach(signal => { process.removeListener(signal, this.shutdownCleanupRef); }); } /** * Calls the `onModuleInit` function on the registered * modules and its children. */ async callInitHook() { const modulesContainer = this.container.getModules(); for (const module of [...modulesContainer.values()].reverse()) { await hooks_1.callModuleInitHook(module); } } /** * Calls the `onModuleDestroy` function on the registered * modules and its children. */ async callDestroyHook() { const modulesContainer = this.container.getModules(); for (const module of modulesContainer.values()) { await hooks_1.callModuleDestroyHook(module); } } /** * Calls the `onApplicationBootstrap` function on the registered * modules and its children. */ async callBootstrapHook() { const modulesContainer = this.container.getModules(); for (const module of [...modulesContainer.values()].reverse()) { await hooks_1.callModuleBootstrapHook(module); } } /** * Calls the `onApplicationShutdown` function on the registered * modules and children. */ async callShutdownHook(signal) { const modulesContainer = this.container.getModules(); for (const module of [...modulesContainer.values()].reverse()) { await hooks_1.callAppShutdownHook(module, signal); } } /** * Calls the `beforeApplicationShutdown` function on the registered * modules and children. */ async callBeforeShutdownHook(signal) { const modulesContainer = this.container.getModules(); for (const module of [...modulesContainer.values()].reverse()) { await hooks_1.callBeforeAppShutdownHook(module, signal); } } find(typeOrToken) { return this.containerScanner.find(typeOrToken); } findInstanceByToken(metatypeOrToken, contextModule) { return this.containerScanner.findInstanceByToken(metatypeOrToken, contextModule); } async resolvePerContext(typeOrToken, contextModule, contextId, options) { let wrapper, collection; if (!(options && options.strict)) { [wrapper, collection] = this.containerScanner.getWrapperCollectionPair(typeOrToken); } else { [ wrapper, collection, ] = this.containerScanner.getWrapperCollectionPairByHost(typeOrToken, contextModule); } const instance = await this.injector.loadPerContext(wrapper.instance, wrapper.host, collection, contextId); if (!instance) { throw new unknown_element_exception_1.UnknownElementException(); } return instance; } } exports.NestApplicationContext = NestApplicationContext;