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