UNPKG

9.96 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.NestApplicationContext = void 0;
4const common_1 = require("@nestjs/common");
5const interfaces_1 = require("@nestjs/common/interfaces");
6const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
7const iterare_1 = require("iterare");
8const constants_1 = require("./constants");
9const invalid_class_scope_exception_1 = require("./errors/exceptions/invalid-class-scope.exception");
10const unknown_element_exception_1 = require("./errors/exceptions/unknown-element.exception");
11const unknown_module_exception_1 = require("./errors/exceptions/unknown-module.exception");
12const context_id_factory_1 = require("./helpers/context-id-factory");
13const hooks_1 = require("./hooks");
14const compiler_1 = require("./injector/compiler");
15const injector_1 = require("./injector/injector");
16const instance_links_host_1 = require("./injector/instance-links-host");
17/**
18 * @publicApi
19 */
20class NestApplicationContext {
21 constructor(container, scope = new Array(), contextModule = null) {
22 this.container = container;
23 this.scope = scope;
24 this.contextModule = contextModule;
25 this.isInitialized = false;
26 this.injector = new injector_1.Injector();
27 this.activeShutdownSignals = new Array();
28 this.moduleCompiler = new compiler_1.ModuleCompiler();
29 }
30 get instanceLinksHost() {
31 if (!this._instanceLinksHost) {
32 this._instanceLinksHost = new instance_links_host_1.InstanceLinksHost(this.container);
33 }
34 return this._instanceLinksHost;
35 }
36 selectContextModule() {
37 const modules = this.container.getModules().values();
38 this.contextModule = modules.next().value;
39 }
40 select(moduleType) {
41 const modulesContainer = this.container.getModules();
42 const contextModuleCtor = this.contextModule.metatype;
43 const scope = this.scope.concat(contextModuleCtor);
44 const moduleTokenFactory = this.container.getModuleTokenFactory();
45 const { type, dynamicMetadata } = this.moduleCompiler.extractMetadata(moduleType);
46 const token = moduleTokenFactory.create(type, dynamicMetadata);
47 const selectedModule = modulesContainer.get(token);
48 if (!selectedModule) {
49 throw new unknown_module_exception_1.UnknownModuleException();
50 }
51 return new NestApplicationContext(this.container, scope, selectedModule);
52 }
53 get(typeOrToken, options = { strict: false }) {
54 return !(options && options.strict)
55 ? this.find(typeOrToken)
56 : this.find(typeOrToken, this.contextModule);
57 }
58 resolve(typeOrToken, contextId = context_id_factory_1.createContextId(), options = { strict: false }) {
59 return this.resolvePerContext(typeOrToken, this.contextModule, contextId, options);
60 }
61 registerRequestByContextId(request, contextId) {
62 this.container.registerRequestProvider(request, contextId);
63 }
64 /**
65 * Initalizes the Nest application.
66 * Calls the Nest lifecycle events.
67 *
68 * @returns {Promise<this>} The NestApplicationContext instance as Promise
69 */
70 async init() {
71 if (this.isInitialized) {
72 return this;
73 }
74 await this.callInitHook();
75 await this.callBootstrapHook();
76 this.isInitialized = true;
77 return this;
78 }
79 async close() {
80 await this.callDestroyHook();
81 await this.callBeforeShutdownHook();
82 await this.dispose();
83 await this.callShutdownHook();
84 this.unsubscribeFromProcessSignals();
85 }
86 useLogger(logger) {
87 common_1.Logger.overrideLogger(logger);
88 }
89 flushLogs() {
90 common_1.Logger.flush();
91 }
92 /**
93 * Enables the usage of shutdown hooks. Will call the
94 * `onApplicationShutdown` function of a provider if the
95 * process receives a shutdown signal.
96 *
97 * @param {ShutdownSignal[]} [signals=[]] The system signals it should listen to
98 *
99 * @returns {this} The Nest application context instance
100 */
101 enableShutdownHooks(signals = []) {
102 if (shared_utils_1.isEmpty(signals)) {
103 signals = Object.keys(common_1.ShutdownSignal).map((key) => common_1.ShutdownSignal[key]);
104 }
105 else {
106 // given signals array should be unique because
107 // process shouldn't listen to the same signal more than once.
108 signals = Array.from(new Set(signals));
109 }
110 signals = iterare_1.iterate(signals)
111 .map((signal) => signal.toString().toUpperCase().trim())
112 // filter out the signals which is already listening to
113 .filter(signal => !this.activeShutdownSignals.includes(signal))
114 .toArray();
115 this.listenToShutdownSignals(signals);
116 return this;
117 }
118 async dispose() {
119 // Nest application context has no server
120 // to dispose, therefore just call a noop
121 return Promise.resolve();
122 }
123 /**
124 * Listens to shutdown signals by listening to
125 * process events
126 *
127 * @param {string[]} signals The system signals it should listen to
128 */
129 listenToShutdownSignals(signals) {
130 const cleanup = async (signal) => {
131 var _a;
132 try {
133 signals.forEach(sig => process.removeListener(sig, cleanup));
134 await this.callDestroyHook();
135 await this.callBeforeShutdownHook(signal);
136 await this.dispose();
137 await this.callShutdownHook(signal);
138 process.kill(process.pid, signal);
139 }
140 catch (err) {
141 common_1.Logger.error(constants_1.MESSAGES.ERROR_DURING_SHUTDOWN, (_a = err) === null || _a === void 0 ? void 0 : _a.stack, NestApplicationContext.name);
142 process.exit(1);
143 }
144 };
145 this.shutdownCleanupRef = cleanup;
146 signals.forEach((signal) => {
147 this.activeShutdownSignals.push(signal);
148 process.on(signal, cleanup);
149 });
150 }
151 /**
152 * Unsubscribes from shutdown signals (process events)
153 */
154 unsubscribeFromProcessSignals() {
155 if (!this.shutdownCleanupRef) {
156 return;
157 }
158 this.activeShutdownSignals.forEach(signal => {
159 process.removeListener(signal, this.shutdownCleanupRef);
160 });
161 }
162 /**
163 * Calls the `onModuleInit` function on the registered
164 * modules and its children.
165 */
166 async callInitHook() {
167 const modulesSortedByDistance = this.getModulesSortedByDistance();
168 for (const module of modulesSortedByDistance) {
169 await hooks_1.callModuleInitHook(module);
170 }
171 }
172 /**
173 * Calls the `onModuleDestroy` function on the registered
174 * modules and its children.
175 */
176 async callDestroyHook() {
177 const modulesSortedByDistance = this.getModulesSortedByDistance();
178 for (const module of modulesSortedByDistance) {
179 await hooks_1.callModuleDestroyHook(module);
180 }
181 }
182 /**
183 * Calls the `onApplicationBootstrap` function on the registered
184 * modules and its children.
185 */
186 async callBootstrapHook() {
187 const modulesSortedByDistance = this.getModulesSortedByDistance();
188 for (const module of modulesSortedByDistance) {
189 await hooks_1.callModuleBootstrapHook(module);
190 }
191 }
192 /**
193 * Calls the `onApplicationShutdown` function on the registered
194 * modules and children.
195 */
196 async callShutdownHook(signal) {
197 const modulesSortedByDistance = this.getModulesSortedByDistance();
198 for (const module of modulesSortedByDistance) {
199 await hooks_1.callAppShutdownHook(module, signal);
200 }
201 }
202 /**
203 * Calls the `beforeApplicationShutdown` function on the registered
204 * modules and children.
205 */
206 async callBeforeShutdownHook(signal) {
207 const modulesSortedByDistance = this.getModulesSortedByDistance();
208 for (const module of modulesSortedByDistance) {
209 await hooks_1.callBeforeAppShutdownHook(module, signal);
210 }
211 }
212 find(typeOrToken, contextModule) {
213 const moduleId = contextModule && contextModule.id;
214 const { wrapperRef } = this.instanceLinksHost.get(typeOrToken, moduleId);
215 if (wrapperRef.scope === interfaces_1.Scope.REQUEST ||
216 wrapperRef.scope === interfaces_1.Scope.TRANSIENT) {
217 throw new invalid_class_scope_exception_1.InvalidClassScopeException(typeOrToken);
218 }
219 return wrapperRef.instance;
220 }
221 async resolvePerContext(typeOrToken, contextModule, contextId, options) {
222 const isStrictModeEnabled = options && options.strict;
223 const instanceLink = isStrictModeEnabled
224 ? this.instanceLinksHost.get(typeOrToken, contextModule.id)
225 : this.instanceLinksHost.get(typeOrToken);
226 const { wrapperRef, collection } = instanceLink;
227 if (wrapperRef.isDependencyTreeStatic() && !wrapperRef.isTransient) {
228 return this.get(typeOrToken, options);
229 }
230 const ctorHost = wrapperRef.instance || { constructor: typeOrToken };
231 const instance = await this.injector.loadPerContext(ctorHost, wrapperRef.host, collection, contextId);
232 if (!instance) {
233 throw new unknown_element_exception_1.UnknownElementException();
234 }
235 return instance;
236 }
237 getModulesSortedByDistance() {
238 if (this._moduleRefsByDistance) {
239 return this._moduleRefsByDistance;
240 }
241 const modulesContainer = this.container.getModules();
242 const compareFn = (a, b) => b.distance - a.distance;
243 this._moduleRefsByDistance = Array.from(modulesContainer.values()).sort(compareFn);
244 return this._moduleRefsByDistance;
245 }
246}
247exports.NestApplicationContext = NestApplicationContext;