UNPKG

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