@twin.org/engine-core 0.0.2-next.3 → 0.0.2-next.5
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 +107 -37
- package/dist/esm/index.mjs +108 -38
- package/dist/types/engineCore.d.ts +22 -8
- package/docs/changelog.md +28 -0
- package/docs/reference/classes/EngineCore.md +73 -13
- package/locales/en.json +2 -1
- package/package.json +3 -2
package/dist/cjs/index.cjs
CHANGED
|
@@ -4,6 +4,7 @@ var core = require('@twin.org/core');
|
|
|
4
4
|
var entity = require('@twin.org/entity');
|
|
5
5
|
var loggingConnectorConsole = require('@twin.org/logging-connector-console');
|
|
6
6
|
var loggingModels = require('@twin.org/logging-models');
|
|
7
|
+
var loggingService = require('@twin.org/logging-service');
|
|
7
8
|
var modules = require('@twin.org/modules');
|
|
8
9
|
var promises = require('node:fs/promises');
|
|
9
10
|
var path = require('node:path');
|
|
@@ -72,10 +73,16 @@ class EngineCore {
|
|
|
72
73
|
* Name for the engine logger.
|
|
73
74
|
*/
|
|
74
75
|
static LOGGER_TYPE_NAME = "engine";
|
|
76
|
+
/**
|
|
77
|
+
* Runtime name for the class in camel case.
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
80
|
+
static _CLASS_NAME_CAMEL_CASE = core.StringHelper.camelCase("EngineCore");
|
|
75
81
|
/**
|
|
76
82
|
* Runtime name for the class.
|
|
83
|
+
* @internal
|
|
77
84
|
*/
|
|
78
|
-
|
|
85
|
+
static _CLASS_NAME = "EngineCore";
|
|
79
86
|
/**
|
|
80
87
|
* The core context.
|
|
81
88
|
*/
|
|
@@ -137,7 +144,7 @@ class EngineCore {
|
|
|
137
144
|
this._typeInitialisers = [];
|
|
138
145
|
this._context = {
|
|
139
146
|
config: options.config,
|
|
140
|
-
|
|
147
|
+
registeredInstances: {},
|
|
141
148
|
componentInstances: [],
|
|
142
149
|
state: { componentStates: {} },
|
|
143
150
|
stateDirty: false
|
|
@@ -174,9 +181,9 @@ class EngineCore {
|
|
|
174
181
|
return false;
|
|
175
182
|
}
|
|
176
183
|
this.setupEngineLogger();
|
|
177
|
-
this.logInfo(core.I18n.formatMessage(
|
|
184
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.starting`));
|
|
178
185
|
if (this._context.config.debug) {
|
|
179
|
-
this.logInfo(core.I18n.formatMessage(
|
|
186
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.debuggingEnabled`));
|
|
180
187
|
}
|
|
181
188
|
let canContinue;
|
|
182
189
|
try {
|
|
@@ -186,11 +193,11 @@ class EngineCore {
|
|
|
186
193
|
await this.initialiseTypeConfig(type, typeConfig, module, method);
|
|
187
194
|
}
|
|
188
195
|
await this.bootstrap();
|
|
189
|
-
this.logInfo(core.I18n.formatMessage(
|
|
196
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStarting`));
|
|
190
197
|
for (const instance of this._context.componentInstances) {
|
|
191
198
|
if (core.Is.function(instance.component.start)) {
|
|
192
199
|
const instanceName = this.getInstanceName(instance);
|
|
193
|
-
this.logInfo(core.I18n.formatMessage(
|
|
200
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStarting`, {
|
|
194
201
|
element: instance.instanceType
|
|
195
202
|
}));
|
|
196
203
|
const componentState = this._context.state.componentStates[instanceName] ?? {};
|
|
@@ -202,9 +209,9 @@ class EngineCore {
|
|
|
202
209
|
}
|
|
203
210
|
}
|
|
204
211
|
}
|
|
205
|
-
this.logInfo(core.I18n.formatMessage(
|
|
212
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsComplete`));
|
|
206
213
|
}
|
|
207
|
-
this.logInfo(core.I18n.formatMessage(
|
|
214
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.started`));
|
|
208
215
|
this._isStarted = true;
|
|
209
216
|
}
|
|
210
217
|
catch (err) {
|
|
@@ -223,14 +230,16 @@ class EngineCore {
|
|
|
223
230
|
* @returns Nothing.
|
|
224
231
|
*/
|
|
225
232
|
async stop() {
|
|
226
|
-
this.logInfo(core.I18n.formatMessage(
|
|
227
|
-
this.logInfo(core.I18n.formatMessage(
|
|
233
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopping`));
|
|
234
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopping`));
|
|
228
235
|
for (const instance of this._context.componentInstances) {
|
|
229
236
|
if (core.Is.function(instance.component.stop)) {
|
|
230
237
|
const instanceName = this.getInstanceName(instance);
|
|
231
238
|
const componentState = this._context.state.componentStates[instanceName] ?? {};
|
|
232
239
|
const lastState = core.ObjectHelper.clone(componentState);
|
|
233
|
-
this.logInfo(core.I18n.formatMessage(
|
|
240
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStopping`, {
|
|
241
|
+
element: instance.instanceType
|
|
242
|
+
}));
|
|
234
243
|
try {
|
|
235
244
|
await instance.component.stop(this._context.state.nodeIdentity, this._loggerTypeName, componentState);
|
|
236
245
|
if (!core.ObjectHelper.equal(lastState, componentState)) {
|
|
@@ -239,15 +248,15 @@ class EngineCore {
|
|
|
239
248
|
}
|
|
240
249
|
}
|
|
241
250
|
catch (err) {
|
|
242
|
-
this.logError(new core.GeneralError(
|
|
251
|
+
this.logError(new core.GeneralError(EngineCore._CLASS_NAME, "componentStopFailed", {
|
|
243
252
|
component: instance.instanceType
|
|
244
253
|
}, core.BaseError.fromError(err)));
|
|
245
254
|
}
|
|
246
255
|
}
|
|
247
256
|
}
|
|
248
257
|
await this.stateSave();
|
|
249
|
-
this.logInfo(core.I18n.formatMessage(
|
|
250
|
-
this.logInfo(core.I18n.formatMessage(
|
|
258
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopped`));
|
|
259
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopped`));
|
|
251
260
|
}
|
|
252
261
|
/**
|
|
253
262
|
* Log info.
|
|
@@ -255,7 +264,7 @@ class EngineCore {
|
|
|
255
264
|
*/
|
|
256
265
|
logInfo(message) {
|
|
257
266
|
this._engineLoggingConnector?.log({
|
|
258
|
-
source:
|
|
267
|
+
source: EngineCore._CLASS_NAME,
|
|
259
268
|
level: "info",
|
|
260
269
|
message
|
|
261
270
|
});
|
|
@@ -274,7 +283,7 @@ class EngineCore {
|
|
|
274
283
|
message += `\n${formattedError.stack}`;
|
|
275
284
|
}
|
|
276
285
|
this._engineLoggingConnector?.log({
|
|
277
|
-
source:
|
|
286
|
+
source: EngineCore._CLASS_NAME,
|
|
278
287
|
level: "error",
|
|
279
288
|
message
|
|
280
289
|
});
|
|
@@ -295,11 +304,48 @@ class EngineCore {
|
|
|
295
304
|
return this._context.state;
|
|
296
305
|
}
|
|
297
306
|
/**
|
|
298
|
-
* Get the
|
|
299
|
-
* @returns The
|
|
307
|
+
* Get all the registered instances.
|
|
308
|
+
* @returns The registered instances.
|
|
300
309
|
*/
|
|
301
|
-
|
|
302
|
-
return this._context.
|
|
310
|
+
getRegisteredInstances() {
|
|
311
|
+
return this._context.registeredInstances;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Get the registered instance type for the component/connector.
|
|
315
|
+
* @param componentConnectorType The type of the component/connector.
|
|
316
|
+
* @param features The requested features of the component, if not specified the default entry will be retrieved.
|
|
317
|
+
* @returns The instance type matching the criteria if one is registered.
|
|
318
|
+
* @throws If a matching instance was not found.
|
|
319
|
+
*/
|
|
320
|
+
getRegisteredInstanceType(componentConnectorType, features) {
|
|
321
|
+
core.Guards.stringValue(EngineCore._CLASS_NAME, "componentConnectorType", componentConnectorType);
|
|
322
|
+
const registeredType = this.getRegisteredInstanceTypeOptional(componentConnectorType, features);
|
|
323
|
+
if (!core.Is.stringValue(registeredType)) {
|
|
324
|
+
throw new core.GeneralError(EngineCore._CLASS_NAME, "instanceTypeNotFound", {
|
|
325
|
+
type: componentConnectorType,
|
|
326
|
+
features: (features ?? ["default"]).join(",")
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
return registeredType;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Get the registered instance type for the component/connector if it exists.
|
|
333
|
+
* @param componentConnectorType The type of the component/connector.
|
|
334
|
+
* @param features The requested features of the component, if not specified the default entry will be retrieved.
|
|
335
|
+
* @returns The instance type matching the criteria if one is registered.
|
|
336
|
+
*/
|
|
337
|
+
getRegisteredInstanceTypeOptional(componentConnectorType, features) {
|
|
338
|
+
let registeredType;
|
|
339
|
+
const registeredTypes = this._context.registeredInstances[componentConnectorType];
|
|
340
|
+
if (core.Is.arrayValue(registeredTypes)) {
|
|
341
|
+
if (core.Is.arrayValue(features)) {
|
|
342
|
+
registeredType = registeredTypes.find(t => t.features?.every(f => features.includes(f)))?.type;
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
registeredType = registeredTypes[0]?.type;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return registeredType;
|
|
303
349
|
}
|
|
304
350
|
/**
|
|
305
351
|
* Get the data required to create a clone of the engine.
|
|
@@ -326,10 +372,10 @@ class EngineCore {
|
|
|
326
372
|
* @param silent Should the clone be silent.
|
|
327
373
|
*/
|
|
328
374
|
populateClone(cloneData, silent) {
|
|
329
|
-
core.Guards.object(
|
|
330
|
-
core.Guards.object(
|
|
331
|
-
core.Guards.object(
|
|
332
|
-
core.Guards.array(
|
|
375
|
+
core.Guards.object(EngineCore._CLASS_NAME, "cloneData", cloneData);
|
|
376
|
+
core.Guards.object(EngineCore._CLASS_NAME, "cloneData.config", cloneData.config);
|
|
377
|
+
core.Guards.object(EngineCore._CLASS_NAME, "cloneData.state", cloneData.state);
|
|
378
|
+
core.Guards.array(EngineCore._CLASS_NAME, "cloneData.typeInitialisers", cloneData.typeInitialisers);
|
|
333
379
|
this._loggerTypeName = cloneData.loggerTypeName;
|
|
334
380
|
this._skipBootstrap = true;
|
|
335
381
|
if (silent ?? false) {
|
|
@@ -337,7 +383,7 @@ class EngineCore {
|
|
|
337
383
|
}
|
|
338
384
|
this._context = {
|
|
339
385
|
config: cloneData.config,
|
|
340
|
-
|
|
386
|
+
registeredInstances: {},
|
|
341
387
|
componentInstances: [],
|
|
342
388
|
state: { componentStates: {} },
|
|
343
389
|
stateDirty: false
|
|
@@ -360,9 +406,20 @@ class EngineCore {
|
|
|
360
406
|
const instanceMethod = await modules.ModuleHelper.getModuleEntry(module, method);
|
|
361
407
|
for (let i = 0; i < typeConfig.length; i++) {
|
|
362
408
|
const instanceType = instanceMethod(this, this._context, typeConfig[i], typeConfig[i].overrideInstanceType);
|
|
363
|
-
if (core.Is.stringValue(instanceType)
|
|
364
|
-
|
|
365
|
-
|
|
409
|
+
if (core.Is.stringValue(instanceType)) {
|
|
410
|
+
this._context.registeredInstances[typeKey] ??= [];
|
|
411
|
+
if (typeConfig[i].isDefault ?? false) {
|
|
412
|
+
this._context.registeredInstances[typeKey].unshift({
|
|
413
|
+
type: instanceType,
|
|
414
|
+
features: typeConfig[i].features
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
this._context.registeredInstances[typeKey].push({
|
|
419
|
+
type: instanceType,
|
|
420
|
+
features: typeConfig[i].features
|
|
421
|
+
});
|
|
422
|
+
}
|
|
366
423
|
}
|
|
367
424
|
}
|
|
368
425
|
}
|
|
@@ -373,7 +430,7 @@ class EngineCore {
|
|
|
373
430
|
*/
|
|
374
431
|
setupEngineLogger() {
|
|
375
432
|
const silent = this._context.config.silent ?? false;
|
|
376
|
-
const
|
|
433
|
+
const engineLoggerConnector = silent
|
|
377
434
|
? new loggingModels.SilentLoggingConnector()
|
|
378
435
|
: new loggingConnectorConsole.ConsoleLoggingConnector({
|
|
379
436
|
config: {
|
|
@@ -383,11 +440,24 @@ class EngineCore {
|
|
|
383
440
|
});
|
|
384
441
|
this._context.componentInstances.push({
|
|
385
442
|
instanceType: this._loggerTypeName,
|
|
386
|
-
component:
|
|
443
|
+
component: engineLoggerConnector
|
|
387
444
|
});
|
|
388
|
-
loggingModels.LoggingConnectorFactory.register(this._loggerTypeName, () =>
|
|
389
|
-
this._engineLoggingConnector =
|
|
390
|
-
this._context.
|
|
445
|
+
loggingModels.LoggingConnectorFactory.register(this._loggerTypeName, () => engineLoggerConnector);
|
|
446
|
+
this._engineLoggingConnector = engineLoggerConnector;
|
|
447
|
+
this._context.registeredInstances.loggingConnector = [
|
|
448
|
+
{
|
|
449
|
+
type: this._loggerTypeName
|
|
450
|
+
}
|
|
451
|
+
];
|
|
452
|
+
const engineLoggerComponent = new loggingService.LoggingService({
|
|
453
|
+
loggingConnectorType: this._loggerTypeName
|
|
454
|
+
});
|
|
455
|
+
core.ComponentFactory.register("logging-service", () => engineLoggerComponent);
|
|
456
|
+
this._context.registeredInstances.loggingComponent = [
|
|
457
|
+
{
|
|
458
|
+
type: "logging-service"
|
|
459
|
+
}
|
|
460
|
+
];
|
|
391
461
|
}
|
|
392
462
|
/**
|
|
393
463
|
* Load the state.
|
|
@@ -436,12 +506,12 @@ class EngineCore {
|
|
|
436
506
|
*/
|
|
437
507
|
async bootstrap() {
|
|
438
508
|
if (!this._skipBootstrap) {
|
|
439
|
-
this.logInfo(core.I18n.formatMessage(
|
|
509
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapStarted`));
|
|
440
510
|
// First bootstrap the components.
|
|
441
511
|
for (const instance of this._context.componentInstances) {
|
|
442
512
|
if (core.Is.function(instance.component.bootstrap)) {
|
|
443
513
|
const instanceName = this.getInstanceName(instance);
|
|
444
|
-
this.logInfo(core.I18n.formatMessage(
|
|
514
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapping`, {
|
|
445
515
|
element: instanceName
|
|
446
516
|
}));
|
|
447
517
|
const componentState = this._context.state.componentStates[instanceName] ?? {};
|
|
@@ -449,7 +519,7 @@ class EngineCore {
|
|
|
449
519
|
const bootstrapSuccess = await instance.component.bootstrap(this._loggerTypeName, componentState);
|
|
450
520
|
// If the bootstrap method failed then throw an error
|
|
451
521
|
if (!bootstrapSuccess) {
|
|
452
|
-
throw new core.GeneralError(
|
|
522
|
+
throw new core.GeneralError(EngineCore._CLASS_NAME, "bootstrapFailed", {
|
|
453
523
|
component: `${instance.component.CLASS_NAME}:${instance.instanceType}`
|
|
454
524
|
});
|
|
455
525
|
}
|
|
@@ -463,7 +533,7 @@ class EngineCore {
|
|
|
463
533
|
if (core.Is.function(this._customBootstrap)) {
|
|
464
534
|
await this._customBootstrap(this, this._context);
|
|
465
535
|
}
|
|
466
|
-
this.logInfo(core.I18n.formatMessage(
|
|
536
|
+
this.logInfo(core.I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapComplete`));
|
|
467
537
|
}
|
|
468
538
|
}
|
|
469
539
|
/**
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { I18n, StringHelper, Is, ObjectHelper, BaseError, GeneralError, ErrorHelper, Guards } from '@twin.org/core';
|
|
1
|
+
import { I18n, StringHelper, Is, ObjectHelper, BaseError, GeneralError, ErrorHelper, Guards, ComponentFactory } from '@twin.org/core';
|
|
2
2
|
import { EntitySchemaFactory } from '@twin.org/entity';
|
|
3
3
|
import { ConsoleLoggingConnector } from '@twin.org/logging-connector-console';
|
|
4
4
|
import { SilentLoggingConnector, LoggingConnectorFactory } from '@twin.org/logging-models';
|
|
5
|
+
import { LoggingService } from '@twin.org/logging-service';
|
|
5
6
|
import { ModuleHelper } from '@twin.org/modules';
|
|
6
7
|
import { readFile, mkdir, writeFile, stat } from 'node:fs/promises';
|
|
7
8
|
import path from 'node:path';
|
|
@@ -70,10 +71,16 @@ class EngineCore {
|
|
|
70
71
|
* Name for the engine logger.
|
|
71
72
|
*/
|
|
72
73
|
static LOGGER_TYPE_NAME = "engine";
|
|
74
|
+
/**
|
|
75
|
+
* Runtime name for the class in camel case.
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
static _CLASS_NAME_CAMEL_CASE = StringHelper.camelCase("EngineCore");
|
|
73
79
|
/**
|
|
74
80
|
* Runtime name for the class.
|
|
81
|
+
* @internal
|
|
75
82
|
*/
|
|
76
|
-
|
|
83
|
+
static _CLASS_NAME = "EngineCore";
|
|
77
84
|
/**
|
|
78
85
|
* The core context.
|
|
79
86
|
*/
|
|
@@ -135,7 +142,7 @@ class EngineCore {
|
|
|
135
142
|
this._typeInitialisers = [];
|
|
136
143
|
this._context = {
|
|
137
144
|
config: options.config,
|
|
138
|
-
|
|
145
|
+
registeredInstances: {},
|
|
139
146
|
componentInstances: [],
|
|
140
147
|
state: { componentStates: {} },
|
|
141
148
|
stateDirty: false
|
|
@@ -172,9 +179,9 @@ class EngineCore {
|
|
|
172
179
|
return false;
|
|
173
180
|
}
|
|
174
181
|
this.setupEngineLogger();
|
|
175
|
-
this.logInfo(I18n.formatMessage(
|
|
182
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.starting`));
|
|
176
183
|
if (this._context.config.debug) {
|
|
177
|
-
this.logInfo(I18n.formatMessage(
|
|
184
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.debuggingEnabled`));
|
|
178
185
|
}
|
|
179
186
|
let canContinue;
|
|
180
187
|
try {
|
|
@@ -184,11 +191,11 @@ class EngineCore {
|
|
|
184
191
|
await this.initialiseTypeConfig(type, typeConfig, module, method);
|
|
185
192
|
}
|
|
186
193
|
await this.bootstrap();
|
|
187
|
-
this.logInfo(I18n.formatMessage(
|
|
194
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStarting`));
|
|
188
195
|
for (const instance of this._context.componentInstances) {
|
|
189
196
|
if (Is.function(instance.component.start)) {
|
|
190
197
|
const instanceName = this.getInstanceName(instance);
|
|
191
|
-
this.logInfo(I18n.formatMessage(
|
|
198
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStarting`, {
|
|
192
199
|
element: instance.instanceType
|
|
193
200
|
}));
|
|
194
201
|
const componentState = this._context.state.componentStates[instanceName] ?? {};
|
|
@@ -200,9 +207,9 @@ class EngineCore {
|
|
|
200
207
|
}
|
|
201
208
|
}
|
|
202
209
|
}
|
|
203
|
-
this.logInfo(I18n.formatMessage(
|
|
210
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsComplete`));
|
|
204
211
|
}
|
|
205
|
-
this.logInfo(I18n.formatMessage(
|
|
212
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.started`));
|
|
206
213
|
this._isStarted = true;
|
|
207
214
|
}
|
|
208
215
|
catch (err) {
|
|
@@ -221,14 +228,16 @@ class EngineCore {
|
|
|
221
228
|
* @returns Nothing.
|
|
222
229
|
*/
|
|
223
230
|
async stop() {
|
|
224
|
-
this.logInfo(I18n.formatMessage(
|
|
225
|
-
this.logInfo(I18n.formatMessage(
|
|
231
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopping`));
|
|
232
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopping`));
|
|
226
233
|
for (const instance of this._context.componentInstances) {
|
|
227
234
|
if (Is.function(instance.component.stop)) {
|
|
228
235
|
const instanceName = this.getInstanceName(instance);
|
|
229
236
|
const componentState = this._context.state.componentStates[instanceName] ?? {};
|
|
230
237
|
const lastState = ObjectHelper.clone(componentState);
|
|
231
|
-
this.logInfo(I18n.formatMessage(
|
|
238
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStopping`, {
|
|
239
|
+
element: instance.instanceType
|
|
240
|
+
}));
|
|
232
241
|
try {
|
|
233
242
|
await instance.component.stop(this._context.state.nodeIdentity, this._loggerTypeName, componentState);
|
|
234
243
|
if (!ObjectHelper.equal(lastState, componentState)) {
|
|
@@ -237,15 +246,15 @@ class EngineCore {
|
|
|
237
246
|
}
|
|
238
247
|
}
|
|
239
248
|
catch (err) {
|
|
240
|
-
this.logError(new GeneralError(
|
|
249
|
+
this.logError(new GeneralError(EngineCore._CLASS_NAME, "componentStopFailed", {
|
|
241
250
|
component: instance.instanceType
|
|
242
251
|
}, BaseError.fromError(err)));
|
|
243
252
|
}
|
|
244
253
|
}
|
|
245
254
|
}
|
|
246
255
|
await this.stateSave();
|
|
247
|
-
this.logInfo(I18n.formatMessage(
|
|
248
|
-
this.logInfo(I18n.formatMessage(
|
|
256
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopped`));
|
|
257
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopped`));
|
|
249
258
|
}
|
|
250
259
|
/**
|
|
251
260
|
* Log info.
|
|
@@ -253,7 +262,7 @@ class EngineCore {
|
|
|
253
262
|
*/
|
|
254
263
|
logInfo(message) {
|
|
255
264
|
this._engineLoggingConnector?.log({
|
|
256
|
-
source:
|
|
265
|
+
source: EngineCore._CLASS_NAME,
|
|
257
266
|
level: "info",
|
|
258
267
|
message
|
|
259
268
|
});
|
|
@@ -272,7 +281,7 @@ class EngineCore {
|
|
|
272
281
|
message += `\n${formattedError.stack}`;
|
|
273
282
|
}
|
|
274
283
|
this._engineLoggingConnector?.log({
|
|
275
|
-
source:
|
|
284
|
+
source: EngineCore._CLASS_NAME,
|
|
276
285
|
level: "error",
|
|
277
286
|
message
|
|
278
287
|
});
|
|
@@ -293,11 +302,48 @@ class EngineCore {
|
|
|
293
302
|
return this._context.state;
|
|
294
303
|
}
|
|
295
304
|
/**
|
|
296
|
-
* Get the
|
|
297
|
-
* @returns The
|
|
305
|
+
* Get all the registered instances.
|
|
306
|
+
* @returns The registered instances.
|
|
298
307
|
*/
|
|
299
|
-
|
|
300
|
-
return this._context.
|
|
308
|
+
getRegisteredInstances() {
|
|
309
|
+
return this._context.registeredInstances;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get the registered instance type for the component/connector.
|
|
313
|
+
* @param componentConnectorType The type of the component/connector.
|
|
314
|
+
* @param features The requested features of the component, if not specified the default entry will be retrieved.
|
|
315
|
+
* @returns The instance type matching the criteria if one is registered.
|
|
316
|
+
* @throws If a matching instance was not found.
|
|
317
|
+
*/
|
|
318
|
+
getRegisteredInstanceType(componentConnectorType, features) {
|
|
319
|
+
Guards.stringValue(EngineCore._CLASS_NAME, "componentConnectorType", componentConnectorType);
|
|
320
|
+
const registeredType = this.getRegisteredInstanceTypeOptional(componentConnectorType, features);
|
|
321
|
+
if (!Is.stringValue(registeredType)) {
|
|
322
|
+
throw new GeneralError(EngineCore._CLASS_NAME, "instanceTypeNotFound", {
|
|
323
|
+
type: componentConnectorType,
|
|
324
|
+
features: (features ?? ["default"]).join(",")
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return registeredType;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Get the registered instance type for the component/connector if it exists.
|
|
331
|
+
* @param componentConnectorType The type of the component/connector.
|
|
332
|
+
* @param features The requested features of the component, if not specified the default entry will be retrieved.
|
|
333
|
+
* @returns The instance type matching the criteria if one is registered.
|
|
334
|
+
*/
|
|
335
|
+
getRegisteredInstanceTypeOptional(componentConnectorType, features) {
|
|
336
|
+
let registeredType;
|
|
337
|
+
const registeredTypes = this._context.registeredInstances[componentConnectorType];
|
|
338
|
+
if (Is.arrayValue(registeredTypes)) {
|
|
339
|
+
if (Is.arrayValue(features)) {
|
|
340
|
+
registeredType = registeredTypes.find(t => t.features?.every(f => features.includes(f)))?.type;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
registeredType = registeredTypes[0]?.type;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return registeredType;
|
|
301
347
|
}
|
|
302
348
|
/**
|
|
303
349
|
* Get the data required to create a clone of the engine.
|
|
@@ -324,10 +370,10 @@ class EngineCore {
|
|
|
324
370
|
* @param silent Should the clone be silent.
|
|
325
371
|
*/
|
|
326
372
|
populateClone(cloneData, silent) {
|
|
327
|
-
Guards.object(
|
|
328
|
-
Guards.object(
|
|
329
|
-
Guards.object(
|
|
330
|
-
Guards.array(
|
|
373
|
+
Guards.object(EngineCore._CLASS_NAME, "cloneData", cloneData);
|
|
374
|
+
Guards.object(EngineCore._CLASS_NAME, "cloneData.config", cloneData.config);
|
|
375
|
+
Guards.object(EngineCore._CLASS_NAME, "cloneData.state", cloneData.state);
|
|
376
|
+
Guards.array(EngineCore._CLASS_NAME, "cloneData.typeInitialisers", cloneData.typeInitialisers);
|
|
331
377
|
this._loggerTypeName = cloneData.loggerTypeName;
|
|
332
378
|
this._skipBootstrap = true;
|
|
333
379
|
if (silent ?? false) {
|
|
@@ -335,7 +381,7 @@ class EngineCore {
|
|
|
335
381
|
}
|
|
336
382
|
this._context = {
|
|
337
383
|
config: cloneData.config,
|
|
338
|
-
|
|
384
|
+
registeredInstances: {},
|
|
339
385
|
componentInstances: [],
|
|
340
386
|
state: { componentStates: {} },
|
|
341
387
|
stateDirty: false
|
|
@@ -358,9 +404,20 @@ class EngineCore {
|
|
|
358
404
|
const instanceMethod = await ModuleHelper.getModuleEntry(module, method);
|
|
359
405
|
for (let i = 0; i < typeConfig.length; i++) {
|
|
360
406
|
const instanceType = instanceMethod(this, this._context, typeConfig[i], typeConfig[i].overrideInstanceType);
|
|
361
|
-
if (Is.stringValue(instanceType)
|
|
362
|
-
|
|
363
|
-
|
|
407
|
+
if (Is.stringValue(instanceType)) {
|
|
408
|
+
this._context.registeredInstances[typeKey] ??= [];
|
|
409
|
+
if (typeConfig[i].isDefault ?? false) {
|
|
410
|
+
this._context.registeredInstances[typeKey].unshift({
|
|
411
|
+
type: instanceType,
|
|
412
|
+
features: typeConfig[i].features
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
this._context.registeredInstances[typeKey].push({
|
|
417
|
+
type: instanceType,
|
|
418
|
+
features: typeConfig[i].features
|
|
419
|
+
});
|
|
420
|
+
}
|
|
364
421
|
}
|
|
365
422
|
}
|
|
366
423
|
}
|
|
@@ -371,7 +428,7 @@ class EngineCore {
|
|
|
371
428
|
*/
|
|
372
429
|
setupEngineLogger() {
|
|
373
430
|
const silent = this._context.config.silent ?? false;
|
|
374
|
-
const
|
|
431
|
+
const engineLoggerConnector = silent
|
|
375
432
|
? new SilentLoggingConnector()
|
|
376
433
|
: new ConsoleLoggingConnector({
|
|
377
434
|
config: {
|
|
@@ -381,11 +438,24 @@ class EngineCore {
|
|
|
381
438
|
});
|
|
382
439
|
this._context.componentInstances.push({
|
|
383
440
|
instanceType: this._loggerTypeName,
|
|
384
|
-
component:
|
|
441
|
+
component: engineLoggerConnector
|
|
385
442
|
});
|
|
386
|
-
LoggingConnectorFactory.register(this._loggerTypeName, () =>
|
|
387
|
-
this._engineLoggingConnector =
|
|
388
|
-
this._context.
|
|
443
|
+
LoggingConnectorFactory.register(this._loggerTypeName, () => engineLoggerConnector);
|
|
444
|
+
this._engineLoggingConnector = engineLoggerConnector;
|
|
445
|
+
this._context.registeredInstances.loggingConnector = [
|
|
446
|
+
{
|
|
447
|
+
type: this._loggerTypeName
|
|
448
|
+
}
|
|
449
|
+
];
|
|
450
|
+
const engineLoggerComponent = new LoggingService({
|
|
451
|
+
loggingConnectorType: this._loggerTypeName
|
|
452
|
+
});
|
|
453
|
+
ComponentFactory.register("logging-service", () => engineLoggerComponent);
|
|
454
|
+
this._context.registeredInstances.loggingComponent = [
|
|
455
|
+
{
|
|
456
|
+
type: "logging-service"
|
|
457
|
+
}
|
|
458
|
+
];
|
|
389
459
|
}
|
|
390
460
|
/**
|
|
391
461
|
* Load the state.
|
|
@@ -434,12 +504,12 @@ class EngineCore {
|
|
|
434
504
|
*/
|
|
435
505
|
async bootstrap() {
|
|
436
506
|
if (!this._skipBootstrap) {
|
|
437
|
-
this.logInfo(I18n.formatMessage(
|
|
507
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapStarted`));
|
|
438
508
|
// First bootstrap the components.
|
|
439
509
|
for (const instance of this._context.componentInstances) {
|
|
440
510
|
if (Is.function(instance.component.bootstrap)) {
|
|
441
511
|
const instanceName = this.getInstanceName(instance);
|
|
442
|
-
this.logInfo(I18n.formatMessage(
|
|
512
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapping`, {
|
|
443
513
|
element: instanceName
|
|
444
514
|
}));
|
|
445
515
|
const componentState = this._context.state.componentStates[instanceName] ?? {};
|
|
@@ -447,7 +517,7 @@ class EngineCore {
|
|
|
447
517
|
const bootstrapSuccess = await instance.component.bootstrap(this._loggerTypeName, componentState);
|
|
448
518
|
// If the bootstrap method failed then throw an error
|
|
449
519
|
if (!bootstrapSuccess) {
|
|
450
|
-
throw new GeneralError(
|
|
520
|
+
throw new GeneralError(EngineCore._CLASS_NAME, "bootstrapFailed", {
|
|
451
521
|
component: `${instance.component.CLASS_NAME}:${instance.instanceType}`
|
|
452
522
|
});
|
|
453
523
|
}
|
|
@@ -461,7 +531,7 @@ class EngineCore {
|
|
|
461
531
|
if (Is.function(this._customBootstrap)) {
|
|
462
532
|
await this._customBootstrap(this, this._context);
|
|
463
533
|
}
|
|
464
|
-
this.logInfo(I18n.formatMessage(
|
|
534
|
+
this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapComplete`));
|
|
465
535
|
}
|
|
466
536
|
}
|
|
467
537
|
/**
|
|
@@ -9,10 +9,6 @@ export declare class EngineCore<C extends IEngineCoreConfig = IEngineCoreConfig,
|
|
|
9
9
|
* Name for the engine logger.
|
|
10
10
|
*/
|
|
11
11
|
static readonly LOGGER_TYPE_NAME: string;
|
|
12
|
-
/**
|
|
13
|
-
* Runtime name for the class.
|
|
14
|
-
*/
|
|
15
|
-
readonly CLASS_NAME: string;
|
|
16
12
|
/**
|
|
17
13
|
* The core context.
|
|
18
14
|
*/
|
|
@@ -61,12 +57,30 @@ export declare class EngineCore<C extends IEngineCoreConfig = IEngineCoreConfig,
|
|
|
61
57
|
*/
|
|
62
58
|
getState(): S;
|
|
63
59
|
/**
|
|
64
|
-
* Get the
|
|
65
|
-
* @returns The
|
|
60
|
+
* Get all the registered instances.
|
|
61
|
+
* @returns The registered instances.
|
|
66
62
|
*/
|
|
67
|
-
|
|
68
|
-
[
|
|
63
|
+
getRegisteredInstances(): {
|
|
64
|
+
[name: string]: {
|
|
65
|
+
type: string;
|
|
66
|
+
features?: string[];
|
|
67
|
+
}[];
|
|
69
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* Get the registered instance type for the component/connector.
|
|
71
|
+
* @param componentConnectorType The type of the component/connector.
|
|
72
|
+
* @param features The requested features of the component, if not specified the default entry will be retrieved.
|
|
73
|
+
* @returns The instance type matching the criteria if one is registered.
|
|
74
|
+
* @throws If a matching instance was not found.
|
|
75
|
+
*/
|
|
76
|
+
getRegisteredInstanceType(componentConnectorType: string, features?: string[]): string;
|
|
77
|
+
/**
|
|
78
|
+
* Get the registered instance type for the component/connector if it exists.
|
|
79
|
+
* @param componentConnectorType The type of the component/connector.
|
|
80
|
+
* @param features The requested features of the component, if not specified the default entry will be retrieved.
|
|
81
|
+
* @returns The instance type matching the criteria if one is registered.
|
|
82
|
+
*/
|
|
83
|
+
getRegisteredInstanceTypeOptional(componentConnectorType: string, features?: string[]): string | undefined;
|
|
70
84
|
/**
|
|
71
85
|
* Get the data required to create a clone of the engine.
|
|
72
86
|
* @returns The clone data.
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @twin.org/engine-core - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.2-next.5](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.4...engine-core-v0.0.2-next.5) (2025-08-14)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add synchronised storage support ([5142e34](https://github.com/twinfoundation/engine/commit/5142e3488f09195cf9f48a9c6c6d1014231a4c2c))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @twin.org/engine-models bumped from 0.0.2-next.4 to 0.0.2-next.5
|
|
16
|
+
|
|
17
|
+
## [0.0.2-next.4](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.3...engine-core-v0.0.2-next.4) (2025-07-25)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* add default logging component for web server ([8ad94f0](https://github.com/twinfoundation/engine/commit/8ad94f0d2d9a5241a8854b1e59fb9a55ce310142))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Dependencies
|
|
26
|
+
|
|
27
|
+
* The following workspace dependencies were updated
|
|
28
|
+
* dependencies
|
|
29
|
+
* @twin.org/engine-models bumped from 0.0.2-next.3 to 0.0.2-next.4
|
|
30
|
+
|
|
3
31
|
## [0.0.2-next.3](https://github.com/twinfoundation/engine/compare/engine-core-v0.0.2-next.2...engine-core-v0.0.2-next.3) (2025-07-24)
|
|
4
32
|
|
|
5
33
|
|
|
@@ -46,14 +46,6 @@ Name for the engine logger.
|
|
|
46
46
|
|
|
47
47
|
***
|
|
48
48
|
|
|
49
|
-
### CLASS\_NAME
|
|
50
|
-
|
|
51
|
-
> `readonly` **CLASS\_NAME**: `string`
|
|
52
|
-
|
|
53
|
-
Runtime name for the class.
|
|
54
|
-
|
|
55
|
-
***
|
|
56
|
-
|
|
57
49
|
### \_context
|
|
58
50
|
|
|
59
51
|
> `protected` **\_context**: `IEngineCoreContext`\<`C`, `S`\>
|
|
@@ -224,21 +216,89 @@ The state of the engine.
|
|
|
224
216
|
|
|
225
217
|
***
|
|
226
218
|
|
|
227
|
-
###
|
|
219
|
+
### getRegisteredInstances()
|
|
228
220
|
|
|
229
|
-
> **
|
|
221
|
+
> **getRegisteredInstances**(): `object`
|
|
230
222
|
|
|
231
|
-
Get the
|
|
223
|
+
Get all the registered instances.
|
|
232
224
|
|
|
233
225
|
#### Returns
|
|
234
226
|
|
|
235
227
|
`object`
|
|
236
228
|
|
|
237
|
-
The
|
|
229
|
+
The registered instances.
|
|
230
|
+
|
|
231
|
+
#### Implementation of
|
|
232
|
+
|
|
233
|
+
`IEngineCore.getRegisteredInstances`
|
|
234
|
+
|
|
235
|
+
***
|
|
236
|
+
|
|
237
|
+
### getRegisteredInstanceType()
|
|
238
|
+
|
|
239
|
+
> **getRegisteredInstanceType**(`componentConnectorType`, `features?`): `string`
|
|
240
|
+
|
|
241
|
+
Get the registered instance type for the component/connector.
|
|
242
|
+
|
|
243
|
+
#### Parameters
|
|
244
|
+
|
|
245
|
+
##### componentConnectorType
|
|
246
|
+
|
|
247
|
+
`string`
|
|
248
|
+
|
|
249
|
+
The type of the component/connector.
|
|
250
|
+
|
|
251
|
+
##### features?
|
|
252
|
+
|
|
253
|
+
`string`[]
|
|
254
|
+
|
|
255
|
+
The requested features of the component, if not specified the default entry will be retrieved.
|
|
256
|
+
|
|
257
|
+
#### Returns
|
|
258
|
+
|
|
259
|
+
`string`
|
|
260
|
+
|
|
261
|
+
The instance type matching the criteria if one is registered.
|
|
262
|
+
|
|
263
|
+
#### Throws
|
|
264
|
+
|
|
265
|
+
If a matching instance was not found.
|
|
266
|
+
|
|
267
|
+
#### Implementation of
|
|
268
|
+
|
|
269
|
+
`IEngineCore.getRegisteredInstanceType`
|
|
270
|
+
|
|
271
|
+
***
|
|
272
|
+
|
|
273
|
+
### getRegisteredInstanceTypeOptional()
|
|
274
|
+
|
|
275
|
+
> **getRegisteredInstanceTypeOptional**(`componentConnectorType`, `features?`): `undefined` \| `string`
|
|
276
|
+
|
|
277
|
+
Get the registered instance type for the component/connector if it exists.
|
|
278
|
+
|
|
279
|
+
#### Parameters
|
|
280
|
+
|
|
281
|
+
##### componentConnectorType
|
|
282
|
+
|
|
283
|
+
`string`
|
|
284
|
+
|
|
285
|
+
The type of the component/connector.
|
|
286
|
+
|
|
287
|
+
##### features?
|
|
288
|
+
|
|
289
|
+
`string`[]
|
|
290
|
+
|
|
291
|
+
The requested features of the component, if not specified the default entry will be retrieved.
|
|
292
|
+
|
|
293
|
+
#### Returns
|
|
294
|
+
|
|
295
|
+
`undefined` \| `string`
|
|
296
|
+
|
|
297
|
+
The instance type matching the criteria if one is registered.
|
|
238
298
|
|
|
239
299
|
#### Implementation of
|
|
240
300
|
|
|
241
|
-
`IEngineCore.
|
|
301
|
+
`IEngineCore.getRegisteredInstanceTypeOptional`
|
|
242
302
|
|
|
243
303
|
***
|
|
244
304
|
|
package/locales/en.json
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
"entityStorageCustomMissing": "Entity storage custom \"{typeCustom}\" missing for component \"{storageName}\"",
|
|
7
7
|
"entityStorageMissing": "Entity storage configuration missing for component \"{storageName}\"",
|
|
8
8
|
"bootstrapFailed": "Bootstrap failed for component \"{component}\", please check the logs for more information",
|
|
9
|
-
"componentStopFailed": "Failed to stop component \"{component}\""
|
|
9
|
+
"componentStopFailed": "Failed to stop component \"{component}\"",
|
|
10
|
+
"instanceTypeNotFound": "Instance type not found for \"{type}\" with features \"{features}\""
|
|
10
11
|
},
|
|
11
12
|
"fileStateStorage": {
|
|
12
13
|
"failedLoading": "Failed to load file state storage from \"{filename}\"",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/engine-core",
|
|
3
|
-
"version": "0.0.2-next.
|
|
3
|
+
"version": "0.0.2-next.5",
|
|
4
4
|
"description": "Engine core.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,10 +17,11 @@
|
|
|
17
17
|
"@twin.org/core": "next",
|
|
18
18
|
"@twin.org/crypto": "next",
|
|
19
19
|
"@twin.org/data-core": "next",
|
|
20
|
-
"@twin.org/engine-models": "0.0.2-next.
|
|
20
|
+
"@twin.org/engine-models": "0.0.2-next.5",
|
|
21
21
|
"@twin.org/entity": "next",
|
|
22
22
|
"@twin.org/logging-connector-console": "next",
|
|
23
23
|
"@twin.org/logging-models": "next",
|
|
24
|
+
"@twin.org/logging-service": "next",
|
|
24
25
|
"@twin.org/modules": "next",
|
|
25
26
|
"@twin.org/nameof": "next"
|
|
26
27
|
},
|