1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const expression_1 = require("@gabliam/expression");
|
4 | const d = require("debug");
|
5 | const _ = require("lodash");
|
6 | const common_1 = require("./common");
|
7 | const constants_1 = require("./constants");
|
8 | const container_1 = require("./container");
|
9 | const loaders_1 = require("./loaders");
|
10 | const metadatas_1 = require("./metadatas");
|
11 | const plugin_list_1 = require("./plugin-list");
|
12 | const reflection_1 = require("./reflection");
|
13 | const registry_1 = require("./registry");
|
14 | const value_extractor_1 = require("./value-extractor");
|
15 | const debug = d('Gabliam:core');
|
16 | const DEFAULT_CONFIG = {
|
17 | config: process.env.GABLIAM_CONFIG_PATH,
|
18 | };
|
19 |
|
20 |
|
21 |
|
22 | class Gabliam {
|
23 | |
24 |
|
25 |
|
26 |
|
27 | constructor(options) {
|
28 | this.container = container_1.createContainer();
|
29 | |
30 |
|
31 |
|
32 | this.registry = new registry_1.Registry();
|
33 | |
34 |
|
35 |
|
36 | this.loaderModule = new loaders_1.LoaderModule();
|
37 | |
38 |
|
39 |
|
40 | this.loaderConfig = new loaders_1.LoaderConfig();
|
41 | |
42 |
|
43 |
|
44 | this.pluginList = new plugin_list_1.PluginList();
|
45 | if (options === undefined) {
|
46 | this.options = DEFAULT_CONFIG;
|
47 | }
|
48 | else {
|
49 | if (_.isString(options)) {
|
50 | this.options = Object.assign({}, DEFAULT_CONFIG, { config: options });
|
51 | }
|
52 | else {
|
53 | this.options = Object.assign({}, DEFAULT_CONFIG, options);
|
54 | }
|
55 | }
|
56 | |
57 |
|
58 |
|
59 | this.container.bind(constants_1.CORE_CONFIG).toConstantValue(this.options);
|
60 | }
|
61 | |
62 |
|
63 |
|
64 |
|
65 |
|
66 | addPlugin(plugin) {
|
67 | this.pluginList.add(plugin);
|
68 | return this;
|
69 | }
|
70 | |
71 |
|
72 |
|
73 |
|
74 |
|
75 | addPlugins(...plugins) {
|
76 | for (const plugin of plugins) {
|
77 | this.addPlugin(plugin);
|
78 | }
|
79 | return this;
|
80 | }
|
81 | |
82 |
|
83 |
|
84 |
|
85 | async build() {
|
86 | this.pluginList.sort();
|
87 | |
88 |
|
89 |
|
90 | await this._initializeConfig();
|
91 | |
92 |
|
93 |
|
94 | this.registry.addRegistry(this.loaderModule.load(this.options.scanPath, this.pluginList.plugins));
|
95 | |
96 |
|
97 |
|
98 | await this._bind();
|
99 | |
100 |
|
101 |
|
102 | await this._loadConfig();
|
103 | for (const plugin of this.pluginList.pluginsWithBuild) {
|
104 | await common_1.toPromise(plugin.build(this.container, this.registry));
|
105 | }
|
106 | return this;
|
107 | }
|
108 | |
109 |
|
110 |
|
111 |
|
112 | async buildAndStart() {
|
113 | await this.build();
|
114 | await this.start();
|
115 | return this;
|
116 | }
|
117 | |
118 |
|
119 |
|
120 |
|
121 | async stopAndDestroy() {
|
122 | await this.stop();
|
123 | await this.destroy();
|
124 | return this;
|
125 | }
|
126 | |
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 | async start() {
|
133 | for (const plugin of this.pluginList.pluginsWithStart) {
|
134 | await common_1.toPromise(plugin.start(this.container, this.registry));
|
135 | }
|
136 | return this;
|
137 | }
|
138 | |
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 | async stop() {
|
145 | for (const plugin of this.pluginList.pluginsWithStop) {
|
146 | await common_1.toPromise(plugin.stop(this.container, this.registry));
|
147 | }
|
148 | return this;
|
149 | }
|
150 | |
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 | async destroy() {
|
157 | for (const plugin of this.pluginList.pluginsWithDestroy) {
|
158 | await common_1.toPromise(plugin.destroy(this.container, this.registry));
|
159 | }
|
160 | const values = this.registry.get(constants_1.TYPE.PreDestroy);
|
161 | const instanceToDestroy = async (value) => {
|
162 | if (value.options) {
|
163 | const instance = this.container.get(value.id);
|
164 | for (const preDestroy of value.options.preDestroys) {
|
165 | await common_1.callInstance(instance, preDestroy);
|
166 | }
|
167 | }
|
168 | };
|
169 | const p = [];
|
170 | for (const value of values) {
|
171 | p.push(instanceToDestroy(value));
|
172 | }
|
173 | await Promise.all(p);
|
174 | return this;
|
175 | }
|
176 | |
177 |
|
178 |
|
179 | async _initializeConfig() {
|
180 | this.config = await this.loaderConfig.load(this.options.config);
|
181 | const config = this.config;
|
182 | this.container.bind(constants_1.APP_CONFIG).toConstantValue(config);
|
183 | this.container
|
184 | .bind(constants_1.VALUE_EXTRACTOR)
|
185 | .toConstantValue(value_extractor_1.configureValueExtractor(this.container));
|
186 | this.container
|
187 | .bind(expression_1.ExpressionParser)
|
188 | .toConstantValue(new expression_1.ExpressionParser(config));
|
189 | }
|
190 | |
191 |
|
192 |
|
193 |
|
194 |
|
195 | async _bind() {
|
196 | debug('_bind');
|
197 | this.registry.getAllAutoBind().forEach(({ id, target }) => this.container
|
198 | .bind(id)
|
199 | .to(target)
|
200 | .inSingletonScope());
|
201 | for (const plugin of this.pluginList.pluginsWithBind) {
|
202 | await common_1.toPromise(plugin.bind(this.container, this.registry));
|
203 | }
|
204 | }
|
205 | |
206 |
|
207 |
|
208 | async _loadConfig() {
|
209 | debug('_loadConfig');
|
210 |
|
211 | let configsRegistry = this.registry.get(constants_1.TYPE.Config);
|
212 | debug('configsRegistry', configsRegistry);
|
213 | if (configsRegistry) {
|
214 | configsRegistry = _.sortBy(configsRegistry, 'options.order');
|
215 | for (const { id: configId } of configsRegistry) {
|
216 |
|
217 | const confInstance = this.container.get(configId);
|
218 | const ctor = confInstance.constructor;
|
219 |
|
220 | const beanMetadatas = reflection_1.reflection.propMetadataOfDecorator(ctor, metadatas_1.Bean);
|
221 |
|
222 | const onMissingBeanMetadatas = reflection_1.reflection.propMetadataOfDecorator(ctor, metadatas_1.OnMissingBean);
|
223 | const beforeCreateMetas = Object.keys(reflection_1.reflection.propMetadataOfDecorator(ctor, metadatas_1.BeforeCreate));
|
224 | const initMetadas = Object.keys(reflection_1.reflection.propMetadataOfDecorator(ctor, metadatas_1.Init));
|
225 |
|
226 | if (Array.isArray(beforeCreateMetas)) {
|
227 |
|
228 | for (const metada of beforeCreateMetas) {
|
229 | await common_1.callInstance(confInstance, metada);
|
230 | }
|
231 | }
|
232 |
|
233 | if (Object.keys(beanMetadatas).length) {
|
234 |
|
235 | for (const [key, beans] of Object.entries(beanMetadatas)) {
|
236 | const onMissingBeans = onMissingBeanMetadatas[key] || [];
|
237 |
|
238 | let allMissing = true;
|
239 |
|
240 | for (const onMissingBean of onMissingBeans) {
|
241 | try {
|
242 | this.container.getAll(onMissingBean.id);
|
243 | allMissing = false;
|
244 | }
|
245 | catch (_a) { }
|
246 | }
|
247 |
|
248 | if (allMissing) {
|
249 | for (const { id } of beans) {
|
250 | const bean = await common_1.callInstance(confInstance, key);
|
251 | this.container.bind(id).toConstantValue(bean);
|
252 | if (bean === undefined || bean.constructor === undefined) {
|
253 | continue;
|
254 | }
|
255 | const preDestroys = Object.keys(reflection_1.reflection.propMetadataOfDecorator(bean.constructor, metadatas_1.PreDestroy));
|
256 |
|
257 | if (preDestroys.length) {
|
258 | this.registry.add(constants_1.TYPE.PreDestroy, {
|
259 | id,
|
260 | target: bean,
|
261 | options: {
|
262 | preDestroys,
|
263 | },
|
264 | });
|
265 | }
|
266 | }
|
267 | }
|
268 | }
|
269 | }
|
270 | if (Array.isArray(initMetadas)) {
|
271 |
|
272 | for (const metada of initMetadas) {
|
273 | await common_1.callInstance(confInstance, metada);
|
274 | }
|
275 | }
|
276 | for (const plugin of this.pluginList.pluginWithConfig) {
|
277 | await common_1.toPromise(plugin.config(this.container, this.registry, confInstance));
|
278 | }
|
279 | }
|
280 | }
|
281 | debug('_loadConfig end');
|
282 | }
|
283 | }
|
284 | exports.Gabliam = Gabliam;
|