@twin.org/engine-core 0.0.2-next.2 → 0.0.2-next.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +228 -96
- package/dist/esm/index.mjs +229 -98
- package/dist/types/engineCore.d.ts +46 -12
- package/dist/types/index.d.ts +1 -0
- package/dist/types/models/IEngineCoreOptions.d.ts +0 -5
- package/dist/types/utils/engineModuleHelper.d.ts +17 -0
- package/docs/changelog.md +252 -0
- package/docs/reference/classes/EngineCore.md +157 -23
- package/docs/reference/classes/EngineModuleHelper.md +55 -0
- package/docs/reference/index.md +1 -0
- package/docs/reference/interfaces/IEngineCoreOptions.md +0 -14
- package/locales/en.json +5 -1
- package/package.json +14 -2
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var node_worker_threads = require('node:worker_threads');
|
|
3
4
|
var core = require('@twin.org/core');
|
|
4
5
|
var entity = require('@twin.org/entity');
|
|
5
6
|
var loggingConnectorConsole = require('@twin.org/logging-connector-console');
|
|
6
7
|
var loggingModels = require('@twin.org/logging-models');
|
|
8
|
+
var loggingService = require('@twin.org/logging-service');
|
|
7
9
|
var modules = require('@twin.org/modules');
|
|
8
10
|
var promises = require('node:fs/promises');
|
|
9
11
|
var path = require('node:path');
|
|
@@ -69,13 +71,14 @@ class MemoryStateStorage {
|
|
|
69
71
|
*/
|
|
70
72
|
class EngineCore {
|
|
71
73
|
/**
|
|
72
|
-
* Name for the engine logger.
|
|
74
|
+
* Name for the engine logger, used for direct console logging.
|
|
73
75
|
*/
|
|
74
|
-
static
|
|
76
|
+
static LOGGING_TYPE_NAME = "engine-logging-service";
|
|
75
77
|
/**
|
|
76
78
|
* Runtime name for the class.
|
|
79
|
+
* @internal
|
|
77
80
|
*/
|
|
78
|
-
|
|
81
|
+
static _CLASS_NAME = "EngineCore";
|
|
79
82
|
/**
|
|
80
83
|
* The core context.
|
|
81
84
|
*/
|
|
@@ -86,20 +89,15 @@ class EngineCore {
|
|
|
86
89
|
*/
|
|
87
90
|
_stateStorage;
|
|
88
91
|
/**
|
|
89
|
-
* The logging
|
|
92
|
+
* The logging component for the engine.
|
|
90
93
|
* @internal
|
|
91
94
|
*/
|
|
92
|
-
|
|
95
|
+
_engineLoggingComponent;
|
|
93
96
|
/**
|
|
94
97
|
* Skip the bootstrap process.
|
|
95
98
|
* @internal
|
|
96
99
|
*/
|
|
97
100
|
_skipBootstrap;
|
|
98
|
-
/**
|
|
99
|
-
* The logger type name to use.
|
|
100
|
-
* @internal
|
|
101
|
-
*/
|
|
102
|
-
_loggerTypeName;
|
|
103
101
|
/**
|
|
104
102
|
* The type initialisers.
|
|
105
103
|
* @internal
|
|
@@ -110,6 +108,11 @@ class EngineCore {
|
|
|
110
108
|
* @internal
|
|
111
109
|
*/
|
|
112
110
|
_isStarted;
|
|
111
|
+
/**
|
|
112
|
+
* Is the engine a clone.
|
|
113
|
+
* @internal
|
|
114
|
+
*/
|
|
115
|
+
_isClone;
|
|
113
116
|
/**
|
|
114
117
|
* Add type initialisers to the engine.
|
|
115
118
|
* @internal
|
|
@@ -133,17 +136,17 @@ class EngineCore {
|
|
|
133
136
|
this._skipBootstrap = options.skipBootstrap ?? false;
|
|
134
137
|
this._populateTypeInitialisers = options.populateTypeInitialisers;
|
|
135
138
|
this._customBootstrap = options.customBootstrap;
|
|
136
|
-
this._loggerTypeName = options.loggerTypeName ?? EngineCore.LOGGER_TYPE_NAME;
|
|
137
139
|
this._typeInitialisers = [];
|
|
138
140
|
this._context = {
|
|
139
141
|
config: options.config,
|
|
140
|
-
|
|
142
|
+
registeredInstances: {},
|
|
141
143
|
componentInstances: [],
|
|
142
|
-
state: {
|
|
144
|
+
state: {},
|
|
143
145
|
stateDirty: false
|
|
144
146
|
};
|
|
145
147
|
this._stateStorage = options.stateStorage;
|
|
146
148
|
this._isStarted = false;
|
|
149
|
+
this._isClone = false;
|
|
147
150
|
if (core.Is.function(this._populateTypeInitialisers)) {
|
|
148
151
|
this._populateTypeInitialisers(this, this._context);
|
|
149
152
|
}
|
|
@@ -151,19 +154,27 @@ class EngineCore {
|
|
|
151
154
|
/**
|
|
152
155
|
* Add a type initialiser.
|
|
153
156
|
* @param type The type to add the initialiser for.
|
|
154
|
-
* @param typeConfig The type config.
|
|
155
157
|
* @param module The name of the module which contains the initialiser method.
|
|
156
158
|
* @param method The name of the method to call.
|
|
157
159
|
*/
|
|
158
|
-
addTypeInitialiser(type,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
160
|
+
addTypeInitialiser(type, module, method) {
|
|
161
|
+
core.Guards.stringValue(EngineCore._CLASS_NAME, "type", type);
|
|
162
|
+
core.Guards.stringValue(EngineCore._CLASS_NAME, "module", module);
|
|
163
|
+
core.Guards.stringValue(EngineCore._CLASS_NAME, "method", method);
|
|
164
|
+
this._typeInitialisers.push({
|
|
165
|
+
type,
|
|
166
|
+
module,
|
|
167
|
+
method
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get the type config for a specific type.
|
|
172
|
+
* @param type The type to get the config for.
|
|
173
|
+
* @returns The type config or undefined if not found.
|
|
174
|
+
*/
|
|
175
|
+
getTypeConfig(type) {
|
|
176
|
+
core.Guards.stringValue(EngineCore._CLASS_NAME, "type", type);
|
|
177
|
+
return this._context.config.types?.[type];
|
|
167
178
|
}
|
|
168
179
|
/**
|
|
169
180
|
* Start the engine core.
|
|
@@ -174,37 +185,30 @@ class EngineCore {
|
|
|
174
185
|
return false;
|
|
175
186
|
}
|
|
176
187
|
this.setupEngineLogger();
|
|
177
|
-
this.logInfo(core.I18n.formatMessage("engineCore.starting
|
|
188
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.starting`));
|
|
178
189
|
if (this._context.config.debug) {
|
|
179
|
-
this.logInfo(core.I18n.formatMessage("engineCore.debuggingEnabled
|
|
190
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.debuggingEnabled`));
|
|
180
191
|
}
|
|
181
192
|
let canContinue;
|
|
182
193
|
try {
|
|
183
194
|
canContinue = await this.stateLoad();
|
|
184
195
|
if (canContinue) {
|
|
185
|
-
for (const { type,
|
|
186
|
-
await this.initialiseTypeConfig(type,
|
|
196
|
+
for (const { type, module, method } of this._typeInitialisers) {
|
|
197
|
+
await this.initialiseTypeConfig(type, module, method);
|
|
187
198
|
}
|
|
188
199
|
await this.bootstrap();
|
|
189
|
-
this.logInfo(core.I18n.formatMessage("engineCore.componentsStarting
|
|
200
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.componentsStarting`));
|
|
190
201
|
for (const instance of this._context.componentInstances) {
|
|
191
202
|
if (core.Is.function(instance.component.start)) {
|
|
192
|
-
|
|
193
|
-
this.logInfo(core.I18n.formatMessage("engineCore.componentStarting", {
|
|
203
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.componentStarting`, {
|
|
194
204
|
element: instance.instanceType
|
|
195
205
|
}));
|
|
196
|
-
|
|
197
|
-
const lastState = core.ObjectHelper.clone(componentState);
|
|
198
|
-
await instance.component.start(this._context.state.nodeIdentity, this._loggerTypeName, componentState);
|
|
199
|
-
if (!core.ObjectHelper.equal(lastState, componentState)) {
|
|
200
|
-
this._context.state.componentStates[instanceName] = componentState;
|
|
201
|
-
this._context.stateDirty = true;
|
|
202
|
-
}
|
|
206
|
+
await instance.component.start(this._context.state.nodeIdentity, EngineCore.LOGGING_TYPE_NAME);
|
|
203
207
|
}
|
|
204
208
|
}
|
|
205
|
-
this.logInfo(core.I18n.formatMessage("engineCore.componentsComplete
|
|
209
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.componentsComplete`));
|
|
206
210
|
}
|
|
207
|
-
this.logInfo(core.I18n.formatMessage("engineCore.started
|
|
211
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.started`));
|
|
208
212
|
this._isStarted = true;
|
|
209
213
|
}
|
|
210
214
|
catch (err) {
|
|
@@ -223,39 +227,55 @@ class EngineCore {
|
|
|
223
227
|
* @returns Nothing.
|
|
224
228
|
*/
|
|
225
229
|
async stop() {
|
|
226
|
-
this.logInfo(core.I18n.formatMessage("engineCore.stopping
|
|
227
|
-
this.logInfo(core.I18n.formatMessage("engineCore.componentsStopping
|
|
230
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.stopping`));
|
|
231
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.componentsStopping`));
|
|
228
232
|
for (const instance of this._context.componentInstances) {
|
|
229
233
|
if (core.Is.function(instance.component.stop)) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
this.logInfo(core.I18n.formatMessage("engineCore.componentStopping", { element: instance.instanceType }));
|
|
234
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.componentStopping`, {
|
|
235
|
+
element: instance.instanceType
|
|
236
|
+
}));
|
|
234
237
|
try {
|
|
235
|
-
await instance.component.stop(this._context.state.nodeIdentity,
|
|
236
|
-
if (!core.ObjectHelper.equal(lastState, componentState)) {
|
|
237
|
-
this._context.state.componentStates[instanceName] = componentState;
|
|
238
|
-
this._context.stateDirty = true;
|
|
239
|
-
}
|
|
238
|
+
await instance.component.stop(this._context.state.nodeIdentity, EngineCore.LOGGING_TYPE_NAME);
|
|
240
239
|
}
|
|
241
240
|
catch (err) {
|
|
242
|
-
this.logError(new core.GeneralError(
|
|
241
|
+
this.logError(new core.GeneralError(EngineCore._CLASS_NAME, "componentStopFailed", {
|
|
243
242
|
component: instance.instanceType
|
|
244
243
|
}, core.BaseError.fromError(err)));
|
|
245
244
|
}
|
|
246
245
|
}
|
|
247
246
|
}
|
|
248
247
|
await this.stateSave();
|
|
249
|
-
this.logInfo(core.I18n.formatMessage("engineCore.componentsStopped
|
|
250
|
-
this.logInfo(core.I18n.formatMessage("engineCore.stopped
|
|
248
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.componentsStopped`));
|
|
249
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.stopped`));
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Is the engine started.
|
|
253
|
+
* @returns True if the engine is started.
|
|
254
|
+
*/
|
|
255
|
+
isStarted() {
|
|
256
|
+
return this._isStarted;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Is this the primary engine instance.
|
|
260
|
+
* @returns True if the engine is the primary instance.
|
|
261
|
+
*/
|
|
262
|
+
isPrimary() {
|
|
263
|
+
return node_worker_threads.isMainThread && !this._isClone;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Is this engine instance a clone.
|
|
267
|
+
* @returns True if the engine instance is a clone.
|
|
268
|
+
*/
|
|
269
|
+
isClone() {
|
|
270
|
+
return this._isClone;
|
|
251
271
|
}
|
|
252
272
|
/**
|
|
253
273
|
* Log info.
|
|
254
274
|
* @param message The message to log.
|
|
255
275
|
*/
|
|
256
276
|
logInfo(message) {
|
|
257
|
-
this.
|
|
258
|
-
source:
|
|
277
|
+
this._engineLoggingComponent?.log({
|
|
278
|
+
source: EngineCore._CLASS_NAME,
|
|
259
279
|
level: "info",
|
|
260
280
|
message
|
|
261
281
|
});
|
|
@@ -273,8 +293,8 @@ class EngineCore {
|
|
|
273
293
|
if (this._context.config.debug && core.Is.stringValue(formattedError.stack)) {
|
|
274
294
|
message += `\n${formattedError.stack}`;
|
|
275
295
|
}
|
|
276
|
-
this.
|
|
277
|
-
source:
|
|
296
|
+
this._engineLoggingComponent?.log({
|
|
297
|
+
source: EngineCore._CLASS_NAME,
|
|
278
298
|
level: "error",
|
|
279
299
|
message
|
|
280
300
|
});
|
|
@@ -295,11 +315,48 @@ class EngineCore {
|
|
|
295
315
|
return this._context.state;
|
|
296
316
|
}
|
|
297
317
|
/**
|
|
298
|
-
* Get the
|
|
299
|
-
* @returns The
|
|
318
|
+
* Get all the registered instances.
|
|
319
|
+
* @returns The registered instances.
|
|
300
320
|
*/
|
|
301
|
-
|
|
302
|
-
return this._context.
|
|
321
|
+
getRegisteredInstances() {
|
|
322
|
+
return this._context.registeredInstances;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Get the registered instance type for the component/connector.
|
|
326
|
+
* @param componentConnectorType The type of the component/connector.
|
|
327
|
+
* @param features The requested features of the component, if not specified the default entry will be retrieved.
|
|
328
|
+
* @returns The instance type matching the criteria if one is registered.
|
|
329
|
+
* @throws If a matching instance was not found.
|
|
330
|
+
*/
|
|
331
|
+
getRegisteredInstanceType(componentConnectorType, features) {
|
|
332
|
+
core.Guards.stringValue(EngineCore._CLASS_NAME, "componentConnectorType", componentConnectorType);
|
|
333
|
+
const registeredType = this.getRegisteredInstanceTypeOptional(componentConnectorType, features);
|
|
334
|
+
if (!core.Is.stringValue(registeredType)) {
|
|
335
|
+
throw new core.GeneralError(EngineCore._CLASS_NAME, "instanceTypeNotFound", {
|
|
336
|
+
type: componentConnectorType,
|
|
337
|
+
features: (features ?? ["default"]).join(",")
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
return registeredType;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Get the registered instance type for the component/connector if it exists.
|
|
344
|
+
* @param componentConnectorType The type of the component/connector.
|
|
345
|
+
* @param features The requested features of the component, if not specified the default entry will be retrieved.
|
|
346
|
+
* @returns The instance type matching the criteria if one is registered.
|
|
347
|
+
*/
|
|
348
|
+
getRegisteredInstanceTypeOptional(componentConnectorType, features) {
|
|
349
|
+
let registeredType;
|
|
350
|
+
const registeredTypes = this._context.registeredInstances[componentConnectorType];
|
|
351
|
+
if (core.Is.arrayValue(registeredTypes)) {
|
|
352
|
+
if (core.Is.arrayValue(features)) {
|
|
353
|
+
registeredType = registeredTypes.find(t => t.features?.every(f => features.includes(f)))?.type;
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
registeredType = registeredTypes[0]?.type;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return registeredType;
|
|
303
360
|
}
|
|
304
361
|
/**
|
|
305
362
|
* Get the data required to create a clone of the engine.
|
|
@@ -315,8 +372,7 @@ class EngineCore {
|
|
|
315
372
|
config: this._context.config,
|
|
316
373
|
state: this._context.state,
|
|
317
374
|
typeInitialisers: this._typeInitialisers,
|
|
318
|
-
entitySchemas
|
|
319
|
-
loggerTypeName: this._loggerTypeName
|
|
375
|
+
entitySchemas
|
|
320
376
|
};
|
|
321
377
|
return cloneData;
|
|
322
378
|
}
|
|
@@ -326,20 +382,20 @@ class EngineCore {
|
|
|
326
382
|
* @param silent Should the clone be silent.
|
|
327
383
|
*/
|
|
328
384
|
populateClone(cloneData, silent) {
|
|
329
|
-
core.Guards.object(
|
|
330
|
-
core.Guards.object(
|
|
331
|
-
core.Guards.object(
|
|
332
|
-
core.Guards.array(
|
|
333
|
-
this._loggerTypeName = cloneData.loggerTypeName;
|
|
385
|
+
core.Guards.object(EngineCore._CLASS_NAME, "cloneData", cloneData);
|
|
386
|
+
core.Guards.object(EngineCore._CLASS_NAME, "cloneData.config", cloneData.config);
|
|
387
|
+
core.Guards.object(EngineCore._CLASS_NAME, "cloneData.state", cloneData.state);
|
|
388
|
+
core.Guards.array(EngineCore._CLASS_NAME, "cloneData.typeInitialisers", cloneData.typeInitialisers);
|
|
334
389
|
this._skipBootstrap = true;
|
|
390
|
+
this._isClone = true;
|
|
335
391
|
if (silent ?? false) {
|
|
336
392
|
cloneData.config.silent = true;
|
|
337
393
|
}
|
|
338
394
|
this._context = {
|
|
339
395
|
config: cloneData.config,
|
|
340
|
-
|
|
396
|
+
registeredInstances: {},
|
|
341
397
|
componentInstances: [],
|
|
342
|
-
state: {
|
|
398
|
+
state: {},
|
|
343
399
|
stateDirty: false
|
|
344
400
|
};
|
|
345
401
|
this._typeInitialisers = cloneData.typeInitialisers;
|
|
@@ -355,14 +411,41 @@ class EngineCore {
|
|
|
355
411
|
* @param instanceMethod The function to initialise the instance.
|
|
356
412
|
* @internal
|
|
357
413
|
*/
|
|
358
|
-
async initialiseTypeConfig(typeKey,
|
|
414
|
+
async initialiseTypeConfig(typeKey, module, method) {
|
|
415
|
+
const typeConfig = this._context.config.types?.[typeKey];
|
|
359
416
|
if (core.Is.arrayValue(typeConfig)) {
|
|
360
417
|
const instanceMethod = await modules.ModuleHelper.getModuleEntry(module, method);
|
|
361
418
|
for (let i = 0; i < typeConfig.length; i++) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
419
|
+
this.logInfo(core.I18n.formatMessage("engineCore.configuring", {
|
|
420
|
+
element: `${typeKey}: ${typeConfig[i].type}`
|
|
421
|
+
}));
|
|
422
|
+
const result = await instanceMethod(this, this._context, typeConfig[i]);
|
|
423
|
+
if (core.Is.stringValue(result.instanceType) && core.Is.object(result.component)) {
|
|
424
|
+
const finalInstanceType = typeConfig[i].overrideInstanceType ?? result.instanceType;
|
|
425
|
+
this._context.componentInstances.push({
|
|
426
|
+
instanceType: finalInstanceType,
|
|
427
|
+
component: result.component
|
|
428
|
+
});
|
|
429
|
+
result.factory?.register(finalInstanceType, () => result.component);
|
|
430
|
+
this._context.registeredInstances[typeKey] ??= [];
|
|
431
|
+
if (typeConfig[i].isDefault ?? false) {
|
|
432
|
+
this._context.registeredInstances[typeKey].unshift({
|
|
433
|
+
type: finalInstanceType,
|
|
434
|
+
features: typeConfig[i].features
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
this._context.registeredInstances[typeKey].push({
|
|
439
|
+
type: finalInstanceType,
|
|
440
|
+
features: typeConfig[i].features
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
throw new core.GeneralError("engineCore", "componentUnknownType", {
|
|
446
|
+
type: typeConfig[i].type,
|
|
447
|
+
componentType: typeKey
|
|
448
|
+
});
|
|
366
449
|
}
|
|
367
450
|
}
|
|
368
451
|
}
|
|
@@ -373,7 +456,7 @@ class EngineCore {
|
|
|
373
456
|
*/
|
|
374
457
|
setupEngineLogger() {
|
|
375
458
|
const silent = this._context.config.silent ?? false;
|
|
376
|
-
const
|
|
459
|
+
const engineLoggerConnector = silent
|
|
377
460
|
? new loggingModels.SilentLoggingConnector()
|
|
378
461
|
: new loggingConnectorConsole.ConsoleLoggingConnector({
|
|
379
462
|
config: {
|
|
@@ -382,12 +465,25 @@ class EngineCore {
|
|
|
382
465
|
}
|
|
383
466
|
});
|
|
384
467
|
this._context.componentInstances.push({
|
|
385
|
-
instanceType:
|
|
386
|
-
component:
|
|
468
|
+
instanceType: EngineCore.LOGGING_TYPE_NAME,
|
|
469
|
+
component: engineLoggerConnector
|
|
387
470
|
});
|
|
388
|
-
loggingModels.LoggingConnectorFactory.register(
|
|
389
|
-
this.
|
|
390
|
-
|
|
471
|
+
loggingModels.LoggingConnectorFactory.register(EngineCore.LOGGING_TYPE_NAME, () => engineLoggerConnector);
|
|
472
|
+
this._context.registeredInstances.loggingConnector = [
|
|
473
|
+
{
|
|
474
|
+
type: EngineCore.LOGGING_TYPE_NAME
|
|
475
|
+
}
|
|
476
|
+
];
|
|
477
|
+
const engineLoggerComponent = new loggingService.LoggingService({
|
|
478
|
+
loggingConnectorType: EngineCore.LOGGING_TYPE_NAME
|
|
479
|
+
});
|
|
480
|
+
this._engineLoggingComponent = engineLoggerComponent;
|
|
481
|
+
core.ComponentFactory.register(EngineCore.LOGGING_TYPE_NAME, () => engineLoggerComponent);
|
|
482
|
+
this._context.registeredInstances.loggingComponent = [
|
|
483
|
+
{
|
|
484
|
+
type: EngineCore.LOGGING_TYPE_NAME
|
|
485
|
+
}
|
|
486
|
+
];
|
|
391
487
|
}
|
|
392
488
|
/**
|
|
393
489
|
* Load the state.
|
|
@@ -397,10 +493,7 @@ class EngineCore {
|
|
|
397
493
|
async stateLoad() {
|
|
398
494
|
if (this._stateStorage) {
|
|
399
495
|
try {
|
|
400
|
-
this._context.state = ((await this._stateStorage.load(this)) ?? {
|
|
401
|
-
componentStates: {}
|
|
402
|
-
});
|
|
403
|
-
this._context.state.componentStates ??= {};
|
|
496
|
+
this._context.state = ((await this._stateStorage.load(this)) ?? {});
|
|
404
497
|
this._context.stateDirty = false;
|
|
405
498
|
return true;
|
|
406
499
|
}
|
|
@@ -436,34 +529,28 @@ class EngineCore {
|
|
|
436
529
|
*/
|
|
437
530
|
async bootstrap() {
|
|
438
531
|
if (!this._skipBootstrap) {
|
|
439
|
-
this.logInfo(core.I18n.formatMessage("engineCore.bootstrapStarted
|
|
532
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.bootstrapStarted`));
|
|
440
533
|
// First bootstrap the components.
|
|
441
534
|
for (const instance of this._context.componentInstances) {
|
|
442
535
|
if (core.Is.function(instance.component.bootstrap)) {
|
|
443
536
|
const instanceName = this.getInstanceName(instance);
|
|
444
|
-
this.logInfo(core.I18n.formatMessage("engineCore.bootstrapping
|
|
537
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.bootstrapping`, {
|
|
445
538
|
element: instanceName
|
|
446
539
|
}));
|
|
447
|
-
const
|
|
448
|
-
const lastState = core.ObjectHelper.clone(componentState);
|
|
449
|
-
const bootstrapSuccess = await instance.component.bootstrap(this._loggerTypeName, componentState);
|
|
540
|
+
const bootstrapSuccess = await instance.component.bootstrap(EngineCore.LOGGING_TYPE_NAME);
|
|
450
541
|
// If the bootstrap method failed then throw an error
|
|
451
542
|
if (!bootstrapSuccess) {
|
|
452
|
-
throw new core.GeneralError(
|
|
543
|
+
throw new core.GeneralError(EngineCore._CLASS_NAME, "bootstrapFailed", {
|
|
453
544
|
component: `${instance.component.CLASS_NAME}:${instance.instanceType}`
|
|
454
545
|
});
|
|
455
546
|
}
|
|
456
|
-
if (!core.ObjectHelper.equal(lastState, componentState)) {
|
|
457
|
-
this._context.state.componentStates[instanceName] = componentState;
|
|
458
|
-
this._context.stateDirty = true;
|
|
459
|
-
}
|
|
460
547
|
}
|
|
461
548
|
}
|
|
462
549
|
// Now perform any custom bootstrap operations
|
|
463
550
|
if (core.Is.function(this._customBootstrap)) {
|
|
464
551
|
await this._customBootstrap(this, this._context);
|
|
465
552
|
}
|
|
466
|
-
this.logInfo(core.I18n.formatMessage("engineCore.bootstrapComplete
|
|
553
|
+
this.logInfo(core.I18n.formatMessage(`${"engineCore"}.bootstrapComplete`));
|
|
467
554
|
}
|
|
468
555
|
}
|
|
469
556
|
/**
|
|
@@ -568,6 +655,51 @@ class FileStateStorage {
|
|
|
568
655
|
}
|
|
569
656
|
}
|
|
570
657
|
|
|
658
|
+
// Copyright 2024 IOTA Stiftung.
|
|
659
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
660
|
+
/**
|
|
661
|
+
* Helper class for engine modules.
|
|
662
|
+
*/
|
|
663
|
+
class EngineModuleHelper {
|
|
664
|
+
/**
|
|
665
|
+
* Runtime name for the class.
|
|
666
|
+
*/
|
|
667
|
+
static CLASS_NAME = "EngineModuleHelper";
|
|
668
|
+
/**
|
|
669
|
+
* Loads an engine component and constructs it with the relevant dependencies and configuration.
|
|
670
|
+
* @param engineCore The engine core.
|
|
671
|
+
* @param engineModuleConfig The configuration for the module.
|
|
672
|
+
* @returns The instantiated component.
|
|
673
|
+
*/
|
|
674
|
+
static async loadComponent(engineCore, engineModuleConfig) {
|
|
675
|
+
const moduleClass = await modules.ModuleHelper.getModuleEntry(engineModuleConfig.moduleName, engineModuleConfig.className);
|
|
676
|
+
const isClass = core.Is.class(moduleClass);
|
|
677
|
+
if (!isClass) {
|
|
678
|
+
throw new core.GeneralError(EngineModuleHelper.CLASS_NAME, "moduleNotClass", {
|
|
679
|
+
moduleName: engineModuleConfig.moduleName,
|
|
680
|
+
className: engineModuleConfig.className
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
const constructorOptions = {};
|
|
684
|
+
if (core.Is.arrayValue(engineModuleConfig.dependencies)) {
|
|
685
|
+
for (const dependency of engineModuleConfig.dependencies) {
|
|
686
|
+
if (dependency.isOptional ?? false) {
|
|
687
|
+
constructorOptions[dependency.propertyName] = engineCore.getRegisteredInstanceType(dependency.componentName, dependency.features);
|
|
688
|
+
}
|
|
689
|
+
else {
|
|
690
|
+
constructorOptions[dependency.propertyName] =
|
|
691
|
+
engineCore.getRegisteredInstanceTypeOptional(dependency.componentName, dependency.features);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
if (core.Is.object(engineModuleConfig.config)) {
|
|
696
|
+
constructorOptions.config = engineModuleConfig.config;
|
|
697
|
+
}
|
|
698
|
+
return new moduleClass(constructorOptions);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
571
702
|
exports.EngineCore = EngineCore;
|
|
703
|
+
exports.EngineModuleHelper = EngineModuleHelper;
|
|
572
704
|
exports.FileStateStorage = FileStateStorage;
|
|
573
705
|
exports.MemoryStateStorage = MemoryStateStorage;
|