UNPKG

7.59 kBJavaScriptView Raw
1"use strict";
2// Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
3// Node module: @loopback/core
4// This file is licensed under the MIT License.
5// License text available at https://opensource.org/licenses/MIT
6Object.defineProperty(exports, "__esModule", { value: true });
7exports.LifeCycleObserverRegistry = exports.DEFAULT_ORDERED_GROUPS = void 0;
8const tslib_1 = require("tslib");
9const context_1 = require("@loopback/context");
10const debug_1 = tslib_1.__importDefault(require("debug"));
11const keys_1 = require("./keys");
12const lifecycle_1 = require("./lifecycle");
13const debug = (0, debug_1.default)('loopback:core:lifecycle');
14exports.DEFAULT_ORDERED_GROUPS = ['server'];
15/**
16 * A context-based registry for life cycle observers
17 */
18let LifeCycleObserverRegistry = class LifeCycleObserverRegistry {
19 constructor(context, observersView, options = {
20 parallel: true,
21 orderedGroups: exports.DEFAULT_ORDERED_GROUPS,
22 }) {
23 this.context = context;
24 this.observersView = observersView;
25 this.options = options;
26 }
27 setOrderedGroups(groups) {
28 this.options.orderedGroups = groups;
29 }
30 /**
31 * Get observer groups ordered by the group
32 */
33 getObserverGroupsByOrder() {
34 const bindings = this.observersView.bindings;
35 const groups = this.sortObserverBindingsByGroup(bindings);
36 if (debug.enabled) {
37 debug('Observer groups: %j', groups.map(g => ({
38 group: g.group,
39 bindings: g.bindings.map(b => b.key),
40 })));
41 }
42 return groups;
43 }
44 /**
45 * Get the group for a given life cycle observer binding
46 * @param binding - Life cycle observer binding
47 */
48 getObserverGroup(binding) {
49 // First check if there is an explicit group name in the tag
50 let group = binding.tagMap[keys_1.CoreTags.LIFE_CYCLE_OBSERVER_GROUP];
51 if (!group) {
52 // Fall back to a tag that matches one of the groups
53 group = this.options.orderedGroups.find(g => binding.tagMap[g] === g);
54 }
55 group = group || '';
56 debug('Binding %s is configured with observer group %s', binding.key, group);
57 return group;
58 }
59 /**
60 * Sort the life cycle observer bindings so that we can start/stop them
61 * in the right order. By default, we can start other observers before servers
62 * and stop them in the reverse order
63 * @param bindings - Life cycle observer bindings
64 */
65 sortObserverBindingsByGroup(bindings) {
66 // Group bindings in a map
67 const groupMap = new Map();
68 (0, context_1.sortBindingsByPhase)(bindings, keys_1.CoreTags.LIFE_CYCLE_OBSERVER_GROUP, this.options.orderedGroups);
69 for (const binding of bindings) {
70 const group = this.getObserverGroup(binding);
71 let bindingsInGroup = groupMap.get(group);
72 if (bindingsInGroup == null) {
73 bindingsInGroup = [];
74 groupMap.set(group, bindingsInGroup);
75 }
76 bindingsInGroup.push(binding);
77 }
78 // Create an array for group entries
79 const groups = [];
80 for (const [group, bindingsInGroup] of groupMap) {
81 groups.push({ group, bindings: bindingsInGroup });
82 }
83 return groups;
84 }
85 /**
86 * Notify an observer group of the given event
87 * @param group - A group of bindings for life cycle observers
88 * @param event - Event name
89 */
90 async notifyObservers(observers, bindings, event) {
91 if (!this.options.parallel) {
92 let index = 0;
93 for (const observer of observers) {
94 debug('Invoking %s observer for binding %s', event, bindings[index].key);
95 index++;
96 await this.invokeObserver(observer, event);
97 }
98 return;
99 }
100 // Parallel invocation
101 const notifiers = observers.map((observer, index) => {
102 debug('Invoking %s observer for binding %s', event, bindings[index].key);
103 return this.invokeObserver(observer, event);
104 });
105 await Promise.all(notifiers);
106 }
107 /**
108 * Invoke an observer for the given event
109 * @param observer - A life cycle observer
110 * @param event - Event name
111 */
112 async invokeObserver(observer, event) {
113 if (typeof observer[event] === 'function') {
114 // Supply `undefined` for legacy callback function expected by
115 // DataSource.stop()
116 await (0, context_1.invokeMethod)(observer, event, this.context, [undefined], {
117 skipInterceptors: true,
118 });
119 }
120 }
121 /**
122 * Emit events to the observer groups
123 * @param events - Event names
124 * @param groups - Observer groups
125 */
126 async notifyGroups(events, groups, reverse = false) {
127 var _a;
128 const observers = await this.observersView.values();
129 const bindings = this.observersView.bindings;
130 const found = observers.some(observer => events.some(e => typeof observer[e] === 'function'));
131 if (!found)
132 return;
133 if (reverse) {
134 // Do not reverse the original `groups` in place
135 groups = [...groups].reverse();
136 }
137 for (const group of groups) {
138 if ((_a = this.options.disabledGroups) === null || _a === void 0 ? void 0 : _a.includes(group.group)) {
139 debug('Notification skipped (Group is disabled): %s', group.group);
140 continue;
141 }
142 const observersForGroup = [];
143 const bindingsInGroup = reverse
144 ? group.bindings.reverse()
145 : group.bindings;
146 for (const binding of bindingsInGroup) {
147 const index = bindings.indexOf(binding);
148 observersForGroup.push(observers[index]);
149 }
150 for (const event of events) {
151 debug('Beginning notification %s of %s...', event);
152 await this.notifyObservers(observersForGroup, group.bindings, event);
153 debug('Finished notification %s of %s', event);
154 }
155 }
156 }
157 /**
158 * Notify all life cycle observers by group of `init`
159 */
160 async init() {
161 debug('Initializing the %s...');
162 const groups = this.getObserverGroupsByOrder();
163 await this.notifyGroups(['init'], groups);
164 }
165 /**
166 * Notify all life cycle observers by group of `start`
167 */
168 async start() {
169 debug('Starting the %s...');
170 const groups = this.getObserverGroupsByOrder();
171 await this.notifyGroups(['start'], groups);
172 }
173 /**
174 * Notify all life cycle observers by group of `stop`
175 */
176 async stop() {
177 debug('Stopping the %s...');
178 const groups = this.getObserverGroupsByOrder();
179 // Stop in the reverse order
180 await this.notifyGroups(['stop'], groups, true);
181 }
182};
183exports.LifeCycleObserverRegistry = LifeCycleObserverRegistry;
184exports.LifeCycleObserverRegistry = LifeCycleObserverRegistry = tslib_1.__decorate([
185 tslib_1.__param(0, context_1.inject.context()),
186 tslib_1.__param(1, context_1.inject.view(lifecycle_1.lifeCycleObserverFilter)),
187 tslib_1.__param(2, (0, context_1.inject)(keys_1.CoreBindings.LIFE_CYCLE_OBSERVER_OPTIONS, { optional: true })),
188 tslib_1.__metadata("design:paramtypes", [context_1.Context,
189 context_1.ContextView, Object])
190], LifeCycleObserverRegistry);
191//# sourceMappingURL=lifecycle-registry.js.map
\No newline at end of file