@twin.org/engine-core 0.0.2-next.25 → 0.0.2-next.27
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/{esm/index.mjs → es/engineCore.js} +125 -260
- package/dist/es/engineCore.js.map +1 -0
- package/dist/es/index.js +8 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/models/IEngineCoreOptions.js +2 -0
- package/dist/es/models/IEngineCoreOptions.js.map +1 -0
- package/dist/es/storage/fileStateStorage.js +92 -0
- package/dist/es/storage/fileStateStorage.js.map +1 -0
- package/dist/es/storage/memoryStateStorage.js +55 -0
- package/dist/es/storage/memoryStateStorage.js.map +1 -0
- package/dist/es/utils/engineModuleHelper.js +46 -0
- package/dist/es/utils/engineModuleHelper.js.map +1 -0
- package/dist/types/engineCore.d.ts +33 -3
- package/dist/types/index.d.ts +5 -5
- package/docs/changelog.md +14 -0
- package/docs/reference/classes/EngineCore.md +110 -4
- package/locales/en.json +7 -6
- package/package.json +38 -9
- package/dist/cjs/index.cjs +0 -713
|
@@ -1,73 +1,18 @@
|
|
|
1
|
-
import { isMainThread } from 'node:worker_threads';
|
|
2
|
-
import { I18n, Is, Guards, BaseError, GeneralError, ErrorHelper, ComponentFactory } from '@twin.org/core';
|
|
3
|
-
import { EntitySchemaFactory } from '@twin.org/entity';
|
|
4
|
-
import { ConsoleLoggingConnector } from '@twin.org/logging-connector-console';
|
|
5
|
-
import { SilentLoggingConnector, LoggingConnectorFactory } from '@twin.org/logging-models';
|
|
6
|
-
import { LoggingService } from '@twin.org/logging-service';
|
|
7
|
-
import { ModuleHelper } from '@twin.org/modules';
|
|
8
|
-
import { readFile, mkdir, writeFile, stat } from 'node:fs/promises';
|
|
9
|
-
import path from 'node:path';
|
|
10
|
-
|
|
11
|
-
// Copyright 2024 IOTA Stiftung.
|
|
12
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
13
|
-
/**
|
|
14
|
-
* Store state in memory.
|
|
15
|
-
*/
|
|
16
|
-
class MemoryStateStorage {
|
|
17
|
-
/**
|
|
18
|
-
* Runtime name for the class.
|
|
19
|
-
*/
|
|
20
|
-
static CLASS_NAME = "MemoryStateStorage";
|
|
21
|
-
/**
|
|
22
|
-
* Readonly mode state file is not updated.
|
|
23
|
-
* @internal
|
|
24
|
-
*/
|
|
25
|
-
_readonlyMode;
|
|
26
|
-
/**
|
|
27
|
-
* The state object.
|
|
28
|
-
* @internal
|
|
29
|
-
*/
|
|
30
|
-
_engineState;
|
|
31
|
-
/**
|
|
32
|
-
* Create a new instance of MemoryStateStorage.
|
|
33
|
-
* @param readonlyMode Whether the file is in read-only mode.
|
|
34
|
-
* @param state The initial state.
|
|
35
|
-
*/
|
|
36
|
-
constructor(readonlyMode = false, state) {
|
|
37
|
-
this._readonlyMode = readonlyMode;
|
|
38
|
-
this._engineState = state;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Method for loading the state.
|
|
42
|
-
* @param engineCore The engine core to load the state for.
|
|
43
|
-
* @returns The state of the engine or undefined if it doesn't exist.
|
|
44
|
-
*/
|
|
45
|
-
async load(engineCore) {
|
|
46
|
-
engineCore.logInfo(I18n.formatMessage(`${"memoryStateStorage"}.loading`, {
|
|
47
|
-
filename: this._engineState
|
|
48
|
-
}));
|
|
49
|
-
return this._engineState;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Method for saving the state.
|
|
53
|
-
* @param engineCore The engine core to save the state for.
|
|
54
|
-
* @param state The state of the engine to save.
|
|
55
|
-
* @returns Nothing.
|
|
56
|
-
*/
|
|
57
|
-
async save(engineCore, state) {
|
|
58
|
-
if (!this._readonlyMode) {
|
|
59
|
-
engineCore.logInfo(I18n.formatMessage(`${"memoryStateStorage"}.saving`));
|
|
60
|
-
this._engineState = state;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
1
|
// Copyright 2024 IOTA Stiftung.
|
|
66
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
import { isMainThread } from "node:worker_threads";
|
|
4
|
+
import { ContextIdStore } from "@twin.org/context";
|
|
5
|
+
import { BaseError, ComponentFactory, ErrorHelper, GeneralError, Guards, I18n, Is } from "@twin.org/core";
|
|
6
|
+
import { EntitySchemaFactory } from "@twin.org/entity";
|
|
7
|
+
import { ConsoleLoggingConnector } from "@twin.org/logging-connector-console";
|
|
8
|
+
import { LoggingConnectorFactory, SilentLoggingConnector } from "@twin.org/logging-models";
|
|
9
|
+
import { LoggingService } from "@twin.org/logging-service";
|
|
10
|
+
import { ModuleHelper } from "@twin.org/modules";
|
|
11
|
+
import { MemoryStateStorage } from "./storage/memoryStateStorage.js";
|
|
67
12
|
/**
|
|
68
13
|
* Core for the engine.
|
|
69
14
|
*/
|
|
70
|
-
class EngineCore {
|
|
15
|
+
export class EngineCore {
|
|
71
16
|
/**
|
|
72
17
|
* Name for the engine logger component, used for direct console logging.
|
|
73
18
|
*/
|
|
@@ -84,6 +29,14 @@ class EngineCore {
|
|
|
84
29
|
* The core context.
|
|
85
30
|
*/
|
|
86
31
|
_context;
|
|
32
|
+
/**
|
|
33
|
+
* The context ID keys.
|
|
34
|
+
*/
|
|
35
|
+
_contextIdKeys;
|
|
36
|
+
/**
|
|
37
|
+
* The context IDs.
|
|
38
|
+
*/
|
|
39
|
+
_contextIds;
|
|
87
40
|
/**
|
|
88
41
|
* The state storage interface.
|
|
89
42
|
* @internal
|
|
@@ -138,6 +91,7 @@ class EngineCore {
|
|
|
138
91
|
this._populateTypeInitialisers = options.populateTypeInitialisers;
|
|
139
92
|
this._customBootstrap = options.customBootstrap;
|
|
140
93
|
this._typeInitialisers = [];
|
|
94
|
+
this._contextIdKeys = [];
|
|
141
95
|
this._context = {
|
|
142
96
|
config: options.config,
|
|
143
97
|
registeredInstances: {},
|
|
@@ -184,6 +138,38 @@ class EngineCore {
|
|
|
184
138
|
Guards.stringValue(EngineCore.CLASS_NAME, "type", type);
|
|
185
139
|
return this._context.config.types?.[type];
|
|
186
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Add a context ID key to the engine.
|
|
143
|
+
* @param key The context ID key.
|
|
144
|
+
*/
|
|
145
|
+
addContextIdKey(key) {
|
|
146
|
+
if (!this._contextIdKeys.includes(key)) {
|
|
147
|
+
this._contextIdKeys.push(key);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get the context ID keys for the engine.
|
|
152
|
+
* @returns The context IDs keys.
|
|
153
|
+
*/
|
|
154
|
+
getContextIdKeys() {
|
|
155
|
+
return this._contextIdKeys;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Add a context ID to the engine.
|
|
159
|
+
* @param key The context ID key.
|
|
160
|
+
* @param value The context ID value.
|
|
161
|
+
*/
|
|
162
|
+
addContextId(key, value) {
|
|
163
|
+
this._contextIds ??= {};
|
|
164
|
+
this._contextIds[key] = value;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Get the context IDs for the engine.
|
|
168
|
+
* @returns The context IDs or undefined if none are set.
|
|
169
|
+
*/
|
|
170
|
+
getContextIds() {
|
|
171
|
+
return this._contextIds;
|
|
172
|
+
}
|
|
187
173
|
/**
|
|
188
174
|
* Start the engine core.
|
|
189
175
|
* @returns True if the start was successful.
|
|
@@ -193,9 +179,9 @@ class EngineCore {
|
|
|
193
179
|
return false;
|
|
194
180
|
}
|
|
195
181
|
this.setupEngineLogger();
|
|
196
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.starting`));
|
|
182
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.starting`));
|
|
197
183
|
if (this._context.config.debug) {
|
|
198
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.debuggingEnabled`));
|
|
184
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.debuggingEnabled`));
|
|
199
185
|
}
|
|
200
186
|
let canContinue;
|
|
201
187
|
try {
|
|
@@ -205,23 +191,36 @@ class EngineCore {
|
|
|
205
191
|
await this.initialiseTypeConfig(type, module, method);
|
|
206
192
|
}
|
|
207
193
|
await this.bootstrap();
|
|
208
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStarting`));
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
194
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStarting`));
|
|
195
|
+
await ContextIdStore.run(this._contextIds ?? {}, async () => {
|
|
196
|
+
for (const instance of this._context.componentInstances) {
|
|
197
|
+
const startMethod = instance.component.start?.bind(instance.component);
|
|
198
|
+
if (Is.function(startMethod)) {
|
|
199
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentStarting`, {
|
|
200
|
+
className: instance.component.className(),
|
|
201
|
+
instanceType: instance.instanceType
|
|
202
|
+
}));
|
|
203
|
+
try {
|
|
204
|
+
await startMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
await this.logError(new GeneralError(EngineCore.CLASS_NAME, "componentStartFailed", {
|
|
208
|
+
className: instance.component.className(),
|
|
209
|
+
instanceType: instance.instanceType
|
|
210
|
+
}, BaseError.fromError(err)));
|
|
211
|
+
throw err;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
215
214
|
}
|
|
216
|
-
}
|
|
217
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsComplete`));
|
|
215
|
+
});
|
|
216
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsComplete`));
|
|
218
217
|
}
|
|
219
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.started`));
|
|
218
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.started`));
|
|
220
219
|
this._isStarted = true;
|
|
221
220
|
}
|
|
222
221
|
catch (err) {
|
|
223
222
|
canContinue = false;
|
|
224
|
-
this.logError(BaseError.fromError(err));
|
|
223
|
+
await this.logError(BaseError.fromError(err));
|
|
225
224
|
}
|
|
226
225
|
finally {
|
|
227
226
|
if (!(await this.stateSave())) {
|
|
@@ -235,26 +234,31 @@ class EngineCore {
|
|
|
235
234
|
* @returns Nothing.
|
|
236
235
|
*/
|
|
237
236
|
async stop() {
|
|
238
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.stopping`));
|
|
239
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopping`));
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
237
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.stopping`));
|
|
238
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopping`));
|
|
239
|
+
await ContextIdStore.run(this._contextIds ?? {}, async () => {
|
|
240
|
+
for (const instance of this._context.componentInstances) {
|
|
241
|
+
const stopMethod = instance.component.stop?.bind(instance.component);
|
|
242
|
+
if (Is.function(stopMethod)) {
|
|
243
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentStopping`, {
|
|
244
|
+
className: instance.component.className(),
|
|
245
|
+
instanceType: instance.instanceType
|
|
246
|
+
}));
|
|
247
|
+
try {
|
|
248
|
+
await stopMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
await this.logError(new GeneralError(EngineCore.CLASS_NAME, "componentStopFailed", {
|
|
252
|
+
className: instance.component.className(),
|
|
253
|
+
instanceType: instance.instanceType
|
|
254
|
+
}, BaseError.fromError(err)));
|
|
255
|
+
}
|
|
252
256
|
}
|
|
253
257
|
}
|
|
254
|
-
}
|
|
258
|
+
});
|
|
255
259
|
await this.stateSave();
|
|
256
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopped`));
|
|
257
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.stopped`));
|
|
260
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopped`));
|
|
261
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.stopped`));
|
|
258
262
|
}
|
|
259
263
|
/**
|
|
260
264
|
* Is the engine started.
|
|
@@ -281,8 +285,8 @@ class EngineCore {
|
|
|
281
285
|
* Log info.
|
|
282
286
|
* @param message The message to log.
|
|
283
287
|
*/
|
|
284
|
-
logInfo(message) {
|
|
285
|
-
this._engineLoggingComponent?.log({
|
|
288
|
+
async logInfo(message) {
|
|
289
|
+
await this._engineLoggingComponent?.log({
|
|
286
290
|
source: EngineCore.CLASS_NAME,
|
|
287
291
|
level: "info",
|
|
288
292
|
message
|
|
@@ -292,7 +296,7 @@ class EngineCore {
|
|
|
292
296
|
* Log error.
|
|
293
297
|
* @param error The error to log.
|
|
294
298
|
*/
|
|
295
|
-
logError(error) {
|
|
299
|
+
async logError(error) {
|
|
296
300
|
const formattedErrors = ErrorHelper.localizeErrors(error);
|
|
297
301
|
for (const formattedError of formattedErrors) {
|
|
298
302
|
let message = Is.stringValue(formattedError.source)
|
|
@@ -301,7 +305,7 @@ class EngineCore {
|
|
|
301
305
|
if (this._context.config.debug && Is.stringValue(formattedError.stack)) {
|
|
302
306
|
message += `\n${formattedError.stack}`;
|
|
303
307
|
}
|
|
304
|
-
this._engineLoggingComponent?.log({
|
|
308
|
+
await this._engineLoggingComponent?.log({
|
|
305
309
|
source: EngineCore.CLASS_NAME,
|
|
306
310
|
level: "error",
|
|
307
311
|
message
|
|
@@ -385,7 +389,8 @@ class EngineCore {
|
|
|
385
389
|
config: this._context.config,
|
|
386
390
|
state: this._context.state,
|
|
387
391
|
typeInitialisers: this._typeInitialisers,
|
|
388
|
-
entitySchemas
|
|
392
|
+
entitySchemas,
|
|
393
|
+
contextIdKeys: this._contextIdKeys
|
|
389
394
|
};
|
|
390
395
|
return cloneData;
|
|
391
396
|
}
|
|
@@ -412,6 +417,7 @@ class EngineCore {
|
|
|
412
417
|
stateDirty: false
|
|
413
418
|
};
|
|
414
419
|
this._typeInitialisers = cloneData.typeInitialisers;
|
|
420
|
+
this._contextIdKeys.push(...cloneData.contextIdKeys);
|
|
415
421
|
for (const schemaName of Object.keys(cloneData.entitySchemas)) {
|
|
416
422
|
EntitySchemaFactory.register(schemaName, () => cloneData.entitySchemas[schemaName]);
|
|
417
423
|
}
|
|
@@ -429,8 +435,9 @@ class EngineCore {
|
|
|
429
435
|
if (Is.arrayValue(typeConfig)) {
|
|
430
436
|
const instanceMethod = await ModuleHelper.getModuleEntry(module, method);
|
|
431
437
|
for (let i = 0; i < typeConfig.length; i++) {
|
|
432
|
-
this.logInfo(I18n.formatMessage("engineCore.configuring", {
|
|
433
|
-
|
|
438
|
+
await this.logInfo(I18n.formatMessage("engineCore.configuring", {
|
|
439
|
+
componentType: typeKey,
|
|
440
|
+
configType: typeConfig[i].type
|
|
434
441
|
}));
|
|
435
442
|
const result = await instanceMethod(this, this._context, typeConfig[i]);
|
|
436
443
|
if (Is.stringValue(result.instanceType) && Is.object(result.component)) {
|
|
@@ -504,7 +511,7 @@ class EngineCore {
|
|
|
504
511
|
return true;
|
|
505
512
|
}
|
|
506
513
|
catch (err) {
|
|
507
|
-
this.logError(BaseError.fromError(err));
|
|
514
|
+
await this.logError(BaseError.fromError(err));
|
|
508
515
|
return false;
|
|
509
516
|
}
|
|
510
517
|
}
|
|
@@ -523,7 +530,7 @@ class EngineCore {
|
|
|
523
530
|
return true;
|
|
524
531
|
}
|
|
525
532
|
catch (err) {
|
|
526
|
-
this.logError(BaseError.fromError(err));
|
|
533
|
+
await this.logError(BaseError.fromError(err));
|
|
527
534
|
}
|
|
528
535
|
return false;
|
|
529
536
|
}
|
|
@@ -535,174 +542,32 @@ class EngineCore {
|
|
|
535
542
|
*/
|
|
536
543
|
async bootstrap() {
|
|
537
544
|
if (!this._skipBootstrap) {
|
|
538
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapStarted`));
|
|
545
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapStarted`));
|
|
539
546
|
// First bootstrap the components.
|
|
540
547
|
for (const instance of this._context.componentInstances) {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapping`, {
|
|
544
|
-
|
|
548
|
+
const bootstrapMethod = instance.component.bootstrap?.bind(instance.component);
|
|
549
|
+
if (Is.function(bootstrapMethod)) {
|
|
550
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapping`, {
|
|
551
|
+
className: instance.component.className(),
|
|
552
|
+
instanceType: instance.instanceType
|
|
545
553
|
}));
|
|
546
|
-
const bootstrapSuccess = await
|
|
554
|
+
const bootstrapSuccess = await bootstrapMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
|
|
547
555
|
// If the bootstrap method failed then throw an error
|
|
548
556
|
if (!bootstrapSuccess) {
|
|
549
557
|
throw new GeneralError(EngineCore.CLASS_NAME, "bootstrapFailed", {
|
|
550
|
-
|
|
558
|
+
className: instance.component.className(),
|
|
559
|
+
instanceType: instance.instanceType
|
|
551
560
|
});
|
|
552
561
|
}
|
|
553
562
|
}
|
|
554
563
|
}
|
|
555
564
|
// Now perform any custom bootstrap operations
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapComplete`));
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Get the instance name.
|
|
564
|
-
* @param instance The instance to get the name for.
|
|
565
|
-
* @param instance.instanceType The instance type.
|
|
566
|
-
* @param instance.component The component.
|
|
567
|
-
* @returns The instance name.
|
|
568
|
-
* @internal
|
|
569
|
-
*/
|
|
570
|
-
getInstanceName(instance) {
|
|
571
|
-
return `${instance.component.CLASS_NAME}-${instance.instanceType}`;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// Copyright 2024 IOTA Stiftung.
|
|
576
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
577
|
-
/**
|
|
578
|
-
* Store state in a file.
|
|
579
|
-
*/
|
|
580
|
-
class FileStateStorage {
|
|
581
|
-
/**
|
|
582
|
-
* Runtime name for the class.
|
|
583
|
-
*/
|
|
584
|
-
static CLASS_NAME = "FileStateStorage";
|
|
585
|
-
/**
|
|
586
|
-
* The filename to store the state.
|
|
587
|
-
* @internal
|
|
588
|
-
*/
|
|
589
|
-
_filename;
|
|
590
|
-
/**
|
|
591
|
-
* Readonly mode state file is not updated.
|
|
592
|
-
* @internal
|
|
593
|
-
*/
|
|
594
|
-
_readonlyMode;
|
|
595
|
-
/**
|
|
596
|
-
* Create a new instance of FileStateStorage.
|
|
597
|
-
* @param filename The filename to store the state.
|
|
598
|
-
* @param readonlyMode Whether the file is in read-only mode.
|
|
599
|
-
*/
|
|
600
|
-
constructor(filename, readonlyMode = false) {
|
|
601
|
-
Guards.stringValue(FileStateStorage.CLASS_NAME, "filename", filename);
|
|
602
|
-
this._filename = filename;
|
|
603
|
-
this._readonlyMode = readonlyMode;
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Method for loading the state.
|
|
607
|
-
* @param engineCore The engine core to load the state for.
|
|
608
|
-
* @returns The state of the engine or undefined if it doesn't exist.
|
|
609
|
-
*/
|
|
610
|
-
async load(engineCore) {
|
|
611
|
-
try {
|
|
612
|
-
engineCore.logInfo(I18n.formatMessage(`${"fileStateStorage"}.loading`, {
|
|
613
|
-
filename: this._filename
|
|
614
|
-
}));
|
|
615
|
-
if (await this.fileExists(this._filename)) {
|
|
616
|
-
const content = await readFile(this._filename, "utf8");
|
|
617
|
-
return JSON.parse(content.toString());
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
catch (err) {
|
|
621
|
-
throw new GeneralError(FileStateStorage.CLASS_NAME, "failedLoading", { filename: this._filename }, BaseError.fromError(err));
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* Method for saving the state.
|
|
626
|
-
* @param engineCore The engine core to save the state for.
|
|
627
|
-
* @param state The state of the engine to save.
|
|
628
|
-
* @returns Nothing.
|
|
629
|
-
*/
|
|
630
|
-
async save(engineCore, state) {
|
|
631
|
-
if (!this._readonlyMode) {
|
|
632
|
-
try {
|
|
633
|
-
engineCore.logInfo(I18n.formatMessage(`${"fileStateStorage"}.saving`, {
|
|
634
|
-
filename: this._filename
|
|
635
|
-
}));
|
|
636
|
-
try {
|
|
637
|
-
await mkdir(path.dirname(this._filename), { recursive: true });
|
|
638
|
-
}
|
|
639
|
-
catch { }
|
|
640
|
-
await writeFile(this._filename, JSON.stringify(state, undefined, "\t"), "utf8");
|
|
565
|
+
const customBootstrap = this._customBootstrap;
|
|
566
|
+
if (Is.function(customBootstrap)) {
|
|
567
|
+
await customBootstrap.call(this, this, this._context);
|
|
641
568
|
}
|
|
642
|
-
|
|
643
|
-
throw new GeneralError(FileStateStorage.CLASS_NAME, "failedSaving", { filename: this._filename }, BaseError.fromError(err));
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
/**
|
|
648
|
-
* Does the specified file exist.
|
|
649
|
-
* @param filename The filename to check for existence.
|
|
650
|
-
* @returns True if the file exists.
|
|
651
|
-
* @internal
|
|
652
|
-
*/
|
|
653
|
-
async fileExists(filename) {
|
|
654
|
-
try {
|
|
655
|
-
const stats = await stat(filename);
|
|
656
|
-
return stats.isFile();
|
|
657
|
-
}
|
|
658
|
-
catch {
|
|
659
|
-
return false;
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
// Copyright 2024 IOTA Stiftung.
|
|
665
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
666
|
-
/**
|
|
667
|
-
* Helper class for engine modules.
|
|
668
|
-
*/
|
|
669
|
-
class EngineModuleHelper {
|
|
670
|
-
/**
|
|
671
|
-
* Runtime name for the class.
|
|
672
|
-
*/
|
|
673
|
-
static CLASS_NAME = "EngineModuleHelper";
|
|
674
|
-
/**
|
|
675
|
-
* Loads an engine component and constructs it with the relevant dependencies and configuration.
|
|
676
|
-
* @param engineCore The engine core.
|
|
677
|
-
* @param engineModuleConfig The configuration for the module.
|
|
678
|
-
* @returns The instantiated component.
|
|
679
|
-
*/
|
|
680
|
-
static async loadComponent(engineCore, engineModuleConfig) {
|
|
681
|
-
const moduleClass = await ModuleHelper.getModuleEntry(engineModuleConfig.moduleName, engineModuleConfig.className);
|
|
682
|
-
const isClass = Is.class(moduleClass);
|
|
683
|
-
if (!isClass) {
|
|
684
|
-
throw new GeneralError(EngineModuleHelper.CLASS_NAME, "moduleNotClass", {
|
|
685
|
-
moduleName: engineModuleConfig.moduleName,
|
|
686
|
-
className: engineModuleConfig.className
|
|
687
|
-
});
|
|
688
|
-
}
|
|
689
|
-
const constructorOptions = {};
|
|
690
|
-
if (Is.arrayValue(engineModuleConfig.dependencies)) {
|
|
691
|
-
for (const dependency of engineModuleConfig.dependencies) {
|
|
692
|
-
if (dependency.isOptional ?? false) {
|
|
693
|
-
constructorOptions[dependency.propertyName] = engineCore.getRegisteredInstanceType(dependency.componentName, dependency.features);
|
|
694
|
-
}
|
|
695
|
-
else {
|
|
696
|
-
constructorOptions[dependency.propertyName] =
|
|
697
|
-
engineCore.getRegisteredInstanceTypeOptional(dependency.componentName, dependency.features);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
if (Is.object(engineModuleConfig.config)) {
|
|
702
|
-
constructorOptions.config = engineModuleConfig.config;
|
|
569
|
+
await this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapComplete`));
|
|
703
570
|
}
|
|
704
|
-
return new moduleClass(constructorOptions);
|
|
705
571
|
}
|
|
706
572
|
}
|
|
707
|
-
|
|
708
|
-
export { EngineCore, EngineModuleHelper, FileStateStorage, MemoryStateStorage };
|
|
573
|
+
//# sourceMappingURL=engineCore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engineCore.js","sourceRoot":"","sources":["../../src/engineCore.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { isMainThread } from \"node:worker_threads\";\nimport { ContextIdStore, type IContextIds } from \"@twin.org/context\";\nimport {\n\tBaseError,\n\tComponentFactory,\n\tErrorHelper,\n\tGeneralError,\n\tGuards,\n\tI18n,\n\ttype IError,\n\tIs\n} from \"@twin.org/core\";\nimport type {\n\tEngineTypeInitialiser,\n\tIEngineCore,\n\tIEngineCoreClone,\n\tIEngineCoreConfig,\n\tIEngineCoreContext,\n\tIEngineCoreTypeConfig,\n\tIEngineState,\n\tIEngineStateStorage\n} from \"@twin.org/engine-models\";\nimport { EntitySchemaFactory, type IEntitySchema } from \"@twin.org/entity\";\nimport { ConsoleLoggingConnector } from \"@twin.org/logging-connector-console\";\nimport {\n\ttype ILoggingComponent,\n\tLoggingConnectorFactory,\n\tSilentLoggingConnector\n} from \"@twin.org/logging-models\";\nimport { LoggingService } from \"@twin.org/logging-service\";\nimport { ModuleHelper } from \"@twin.org/modules\";\nimport { nameof, nameofCamelCase } from \"@twin.org/nameof\";\nimport type { IEngineCoreOptions } from \"./models/IEngineCoreOptions.js\";\nimport { MemoryStateStorage } from \"./storage/memoryStateStorage.js\";\n\n/**\n * Core for the engine.\n */\nexport class EngineCore<\n\tC extends IEngineCoreConfig = IEngineCoreConfig,\n\tS extends IEngineState = IEngineState\n> implements IEngineCore<C, S>\n{\n\t/**\n\t * Name for the engine logger component, used for direct console logging.\n\t */\n\tpublic static readonly LOGGING_COMPONENT_TYPE_NAME: string = \"engine-logging-service\";\n\n\t/**\n\t * Name for the engine logger connector, used for direct console logging.\n\t */\n\tpublic static readonly LOGGING_CONNECTOR_TYPE_NAME: string = \"engine-logging-connector\";\n\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<EngineCore>();\n\n\t/**\n\t * The core context.\n\t */\n\tprotected _context: IEngineCoreContext<C, S>;\n\n\t/**\n\t * The context ID keys.\n\t */\n\tprotected readonly _contextIdKeys: string[];\n\n\t/**\n\t * The context IDs.\n\t */\n\tprotected _contextIds?: IContextIds;\n\n\t/**\n\t * The state storage interface.\n\t * @internal\n\t */\n\tprivate _stateStorage?: IEngineStateStorage<S>;\n\n\t/**\n\t * The logging component for the engine.\n\t * @internal\n\t */\n\tprivate _engineLoggingComponent?: ILoggingComponent;\n\n\t/**\n\t * Skip the bootstrap process.\n\t * @internal\n\t */\n\tprivate _skipBootstrap?: boolean;\n\n\t/**\n\t * The type initialisers.\n\t * @internal\n\t */\n\tprivate _typeInitialisers: {\n\t\ttype: string;\n\t\tmodule: string;\n\t\tmethod: string;\n\t}[];\n\n\t/**\n\t * Is the engine started.\n\t * @internal\n\t */\n\tprivate _isStarted: boolean;\n\n\t/**\n\t * Is the engine a clone.\n\t * @internal\n\t */\n\tprivate _isClone: boolean;\n\n\t/**\n\t * Add type initialisers to the engine.\n\t * @internal\n\t */\n\tprivate readonly _populateTypeInitialisers?: (\n\t\tengineCore: IEngineCore<C, S>,\n\t\tcontext: IEngineCoreContext<C, S>\n\t) => void;\n\n\t/**\n\t * Method for bootstrapping any data for the engine.\n\t * @internal\n\t */\n\tprivate readonly _customBootstrap?: (\n\t\tengineCore: IEngineCore<C, S>,\n\t\tcontext: IEngineCoreContext<C, S>\n\t) => Promise<void>;\n\n\t/**\n\t * Create a new instance of EngineCore.\n\t * @param options The options for the engine.\n\t */\n\tconstructor(options?: IEngineCoreOptions<C, S>) {\n\t\toptions = options ?? {};\n\t\toptions.config = options.config ?? ({} as C);\n\t\toptions.config.debug = options.config.debug ?? false;\n\t\toptions.config.silent = options.config.silent ?? false;\n\t\toptions.config.types ??= {};\n\n\t\tthis._skipBootstrap = options.skipBootstrap ?? false;\n\t\tthis._populateTypeInitialisers = options.populateTypeInitialisers;\n\t\tthis._customBootstrap = options.customBootstrap;\n\t\tthis._typeInitialisers = [];\n\t\tthis._contextIdKeys = [];\n\n\t\tthis._context = {\n\t\t\tconfig: options.config,\n\t\t\tregisteredInstances: {},\n\t\t\tcomponentInstances: [],\n\t\t\tstate: {} as S,\n\t\t\tstateDirty: false\n\t\t};\n\t\tthis._stateStorage = options.stateStorage;\n\t\tthis._isStarted = false;\n\t\tthis._isClone = false;\n\n\t\tif (Is.function(this._populateTypeInitialisers)) {\n\t\t\tthis._populateTypeInitialisers(this, this._context);\n\t\t}\n\t}\n\n\t/**\n\t * Add a type initialiser.\n\t * @param type The type to add the initialiser for.\n\t * @param module The name of the module which contains the initialiser method.\n\t * @param method The name of the method to call.\n\t */\n\tpublic addTypeInitialiser(type: string, module: string, method: string): void {\n\t\tGuards.stringValue(EngineCore.CLASS_NAME, nameof(type), type);\n\t\tGuards.stringValue(EngineCore.CLASS_NAME, nameof(module), module);\n\t\tGuards.stringValue(EngineCore.CLASS_NAME, nameof(method), method);\n\n\t\tconst currentIndex = this._typeInitialisers.findIndex(t => t.type === type);\n\t\tif (currentIndex >= 0) {\n\t\t\tthis._typeInitialisers[currentIndex].module = module;\n\t\t\tthis._typeInitialisers[currentIndex].method = method;\n\t\t} else {\n\t\t\tthis._typeInitialisers.push({\n\t\t\t\ttype,\n\t\t\t\tmodule,\n\t\t\t\tmethod\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Get the type config for a specific type.\n\t * @param type The type to get the config for.\n\t * @returns The type config or undefined if not found.\n\t */\n\tpublic getTypeConfig(type: string): IEngineCoreTypeConfig[] | undefined {\n\t\tGuards.stringValue(EngineCore.CLASS_NAME, nameof(type), type);\n\t\treturn this._context.config.types?.[type];\n\t}\n\n\t/**\n\t * Add a context ID key to the engine.\n\t * @param key The context ID key.\n\t */\n\tpublic addContextIdKey(key: string): void {\n\t\tif (!this._contextIdKeys.includes(key)) {\n\t\t\tthis._contextIdKeys.push(key);\n\t\t}\n\t}\n\n\t/**\n\t * Get the context ID keys for the engine.\n\t * @returns The context IDs keys.\n\t */\n\tpublic getContextIdKeys(): string[] {\n\t\treturn this._contextIdKeys;\n\t}\n\n\t/**\n\t * Add a context ID to the engine.\n\t * @param key The context ID key.\n\t * @param value The context ID value.\n\t */\n\tpublic addContextId(key: string, value: string): void {\n\t\tthis._contextIds ??= {};\n\t\tthis._contextIds[key] = value;\n\t}\n\n\t/**\n\t * Get the context IDs for the engine.\n\t * @returns The context IDs or undefined if none are set.\n\t */\n\tpublic getContextIds(): IContextIds | undefined {\n\t\treturn this._contextIds;\n\t}\n\n\t/**\n\t * Start the engine core.\n\t * @returns True if the start was successful.\n\t */\n\tpublic async start(): Promise<boolean> {\n\t\tif (this._isStarted) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.setupEngineLogger();\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.starting`));\n\n\t\tif (this._context.config.debug) {\n\t\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.debuggingEnabled`));\n\t\t}\n\n\t\tlet canContinue;\n\t\ttry {\n\t\t\tcanContinue = await this.stateLoad();\n\n\t\t\tif (canContinue) {\n\t\t\t\tfor (const { type, module, method } of this._typeInitialisers) {\n\t\t\t\t\tawait this.initialiseTypeConfig(type, module, method);\n\t\t\t\t}\n\n\t\t\t\tawait this.bootstrap();\n\n\t\t\t\tawait this.logInfo(\n\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentsStarting`)\n\t\t\t\t);\n\n\t\t\t\tawait ContextIdStore.run(this._contextIds ?? {}, async () => {\n\t\t\t\t\tfor (const instance of this._context.componentInstances) {\n\t\t\t\t\t\tconst startMethod = instance.component.start?.bind(instance.component);\n\t\t\t\t\t\tif (Is.function(startMethod)) {\n\t\t\t\t\t\t\tawait this.logInfo(\n\t\t\t\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentStarting`, {\n\t\t\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait startMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tawait this.logError(\n\t\t\t\t\t\t\t\t\tnew GeneralError(\n\t\t\t\t\t\t\t\t\t\tEngineCore.CLASS_NAME,\n\t\t\t\t\t\t\t\t\t\t\"componentStartFailed\",\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tBaseError.fromError(err)\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tthrow err;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tawait this.logInfo(\n\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentsComplete`)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.started`));\n\t\t\tthis._isStarted = true;\n\t\t} catch (err) {\n\t\t\tcanContinue = false;\n\t\t\tawait this.logError(BaseError.fromError(err));\n\t\t} finally {\n\t\t\tif (!(await this.stateSave())) {\n\t\t\t\tcanContinue = false;\n\t\t\t}\n\t\t}\n\n\t\treturn canContinue;\n\t}\n\n\t/**\n\t * Stop the engine core.\n\t * @returns Nothing.\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.stopping`));\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentsStopping`));\n\n\t\tawait ContextIdStore.run(this._contextIds ?? {}, async () => {\n\t\t\tfor (const instance of this._context.componentInstances) {\n\t\t\t\tconst stopMethod = instance.component.stop?.bind(instance.component);\n\t\t\t\tif (Is.function(stopMethod)) {\n\t\t\t\t\tawait this.logInfo(\n\t\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentStopping`, {\n\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait stopMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tawait this.logError(\n\t\t\t\t\t\t\tnew GeneralError(\n\t\t\t\t\t\t\t\tEngineCore.CLASS_NAME,\n\t\t\t\t\t\t\t\t\"componentStopFailed\",\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tBaseError.fromError(err)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tawait this.stateSave();\n\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.componentsStopped`));\n\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.stopped`));\n\t}\n\n\t/**\n\t * Is the engine started.\n\t * @returns True if the engine is started.\n\t */\n\tpublic isStarted(): boolean {\n\t\treturn this._isStarted;\n\t}\n\n\t/**\n\t * Is this the primary engine instance.\n\t * @returns True if the engine is the primary instance.\n\t */\n\tpublic isPrimary(): boolean {\n\t\treturn isMainThread && !this._isClone;\n\t}\n\n\t/**\n\t * Is this engine instance a clone.\n\t * @returns True if the engine instance is a clone.\n\t */\n\tpublic isClone(): boolean {\n\t\treturn this._isClone;\n\t}\n\n\t/**\n\t * Log info.\n\t * @param message The message to log.\n\t */\n\tpublic async logInfo(message: string): Promise<void> {\n\t\tawait this._engineLoggingComponent?.log({\n\t\t\tsource: EngineCore.CLASS_NAME,\n\t\t\tlevel: \"info\",\n\t\t\tmessage\n\t\t});\n\t}\n\n\t/**\n\t * Log error.\n\t * @param error The error to log.\n\t */\n\tpublic async logError(error: IError): Promise<void> {\n\t\tconst formattedErrors = ErrorHelper.localizeErrors(error);\n\t\tfor (const formattedError of formattedErrors) {\n\t\t\tlet message = Is.stringValue(formattedError.source)\n\t\t\t\t? `${formattedError.source}: ${formattedError.message}`\n\t\t\t\t: formattedError.message;\n\t\t\tif (this._context.config.debug && Is.stringValue(formattedError.stack)) {\n\t\t\t\tmessage += `\\n${formattedError.stack}`;\n\t\t\t}\n\t\t\tawait this._engineLoggingComponent?.log({\n\t\t\t\tsource: EngineCore.CLASS_NAME,\n\t\t\t\tlevel: \"error\",\n\t\t\t\tmessage\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Get the config for the engine.\n\t * @returns The config for the engine.\n\t */\n\tpublic getConfig(): C {\n\t\treturn this._context.config;\n\t}\n\n\t/**\n\t * Get the state of the engine.\n\t * @returns The state of the engine.\n\t */\n\tpublic getState(): S {\n\t\treturn this._context.state;\n\t}\n\n\t/**\n\t * Get all the registered instances.\n\t * @returns The registered instances.\n\t */\n\tpublic getRegisteredInstances(): {\n\t\t[name: string]: {\n\t\t\ttype: string;\n\t\t\tisDefault?: boolean;\n\t\t\tfeatures?: string[];\n\t\t}[];\n\t} {\n\t\treturn this._context.registeredInstances;\n\t}\n\n\t/**\n\t * Get the registered instance type for the component/connector.\n\t * @param componentConnectorType The type of the component/connector.\n\t * @param features The requested features of the component, if not specified the default entry will be retrieved.\n\t * @returns The instance type matching the criteria if one is registered.\n\t * @throws If a matching instance was not found.\n\t */\n\tpublic getRegisteredInstanceType(componentConnectorType: string, features?: string[]): string {\n\t\tGuards.stringValue(\n\t\t\tEngineCore.CLASS_NAME,\n\t\t\tnameof(componentConnectorType),\n\t\t\tcomponentConnectorType\n\t\t);\n\n\t\tconst registeredType = this.getRegisteredInstanceTypeOptional(componentConnectorType, features);\n\n\t\tif (!Is.stringValue(registeredType)) {\n\t\t\tthrow new GeneralError(EngineCore.CLASS_NAME, \"instanceTypeNotFound\", {\n\t\t\t\ttype: componentConnectorType,\n\t\t\t\tfeatures: (features ?? [\"default\"]).join(\",\")\n\t\t\t});\n\t\t}\n\n\t\treturn registeredType;\n\t}\n\n\t/**\n\t * Get the registered instance type for the component/connector if it exists.\n\t * @param componentConnectorType The type of the component/connector.\n\t * @param features The requested features of the component, if not specified the default entry will be retrieved.\n\t * @returns The instance type matching the criteria if one is registered.\n\t */\n\tpublic getRegisteredInstanceTypeOptional(\n\t\tcomponentConnectorType: string,\n\t\tfeatures?: string[]\n\t): string | undefined {\n\t\tlet registeredType: string | undefined;\n\n\t\tconst registeredTypes = this._context.registeredInstances[componentConnectorType];\n\t\tif (Is.arrayValue(registeredTypes)) {\n\t\t\tif (Is.arrayValue(features)) {\n\t\t\t\tregisteredType = registeredTypes.find(t =>\n\t\t\t\t\tt.features?.every(f => features.includes(f))\n\t\t\t\t)?.type;\n\t\t\t} else {\n\t\t\t\t// First look for the default entry\n\t\t\t\tregisteredType = registeredTypes.find(t => t.isDefault)?.type;\n\n\t\t\t\t// Can't find a default so just use the first entry\n\t\t\t\tif (!Is.stringValue(registeredType)) {\n\t\t\t\t\tregisteredType = registeredTypes[0]?.type;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn registeredType;\n\t}\n\n\t/**\n\t * Get the data required to create a clone of the engine.\n\t * @returns The clone data.\n\t */\n\tpublic getCloneData(): IEngineCoreClone<C, S> {\n\t\tconst entitySchemas: {\n\t\t\t[schema: string]: IEntitySchema;\n\t\t} = {};\n\n\t\tconst entitySchemaNames = EntitySchemaFactory.names();\n\t\tfor (const schemaName of entitySchemaNames) {\n\t\t\tentitySchemas[schemaName] = EntitySchemaFactory.get(schemaName);\n\t\t}\n\n\t\tconst cloneData: IEngineCoreClone<C, S> = {\n\t\t\tconfig: this._context.config,\n\t\t\tstate: this._context.state,\n\t\t\ttypeInitialisers: this._typeInitialisers,\n\t\t\tentitySchemas,\n\t\t\tcontextIdKeys: this._contextIdKeys\n\t\t};\n\n\t\treturn cloneData;\n\t}\n\n\t/**\n\t * Populate the engine from the clone data.\n\t * @param cloneData The clone data to populate from.\n\t * @param silent Should the clone be silent.\n\t */\n\tpublic populateClone(cloneData: IEngineCoreClone<C, S>, silent?: boolean): void {\n\t\tGuards.object(EngineCore.CLASS_NAME, nameof(cloneData), cloneData);\n\t\tGuards.object(EngineCore.CLASS_NAME, nameof(cloneData.config), cloneData.config);\n\t\tGuards.object(EngineCore.CLASS_NAME, nameof(cloneData.state), cloneData.state);\n\t\tGuards.array(\n\t\t\tEngineCore.CLASS_NAME,\n\t\t\tnameof(cloneData.typeInitialisers),\n\t\t\tcloneData.typeInitialisers\n\t\t);\n\n\t\tthis._skipBootstrap = true;\n\t\tthis._isClone = true;\n\n\t\tif (silent ?? false) {\n\t\t\tcloneData.config.silent = true;\n\t\t}\n\n\t\tthis._context = {\n\t\t\tconfig: cloneData.config,\n\t\t\tregisteredInstances: {},\n\t\t\tcomponentInstances: [],\n\t\t\tstate: {} as S,\n\t\t\tstateDirty: false\n\t\t};\n\n\t\tthis._typeInitialisers = cloneData.typeInitialisers;\n\t\tthis._contextIdKeys.push(...cloneData.contextIdKeys);\n\n\t\tfor (const schemaName of Object.keys(cloneData.entitySchemas)) {\n\t\t\tEntitySchemaFactory.register(schemaName, () => cloneData.entitySchemas[schemaName]);\n\t\t}\n\n\t\tthis._stateStorage = new MemoryStateStorage(true, cloneData.state);\n\t\tthis._isStarted = false;\n\t}\n\n\t/**\n\t * Initialise the types from connector.\n\t * @param typeKey The key for the default types.\n\t * @param instanceMethod The function to initialise the instance.\n\t * @internal\n\t */\n\tprivate async initialiseTypeConfig(\n\t\ttypeKey: string,\n\t\tmodule: string,\n\t\tmethod: string\n\t): Promise<void> {\n\t\tconst typeConfig: IEngineCoreTypeConfig[] | undefined = this._context.config.types?.[typeKey];\n\n\t\tif (Is.arrayValue(typeConfig)) {\n\t\t\tconst instanceMethod = await ModuleHelper.getModuleEntry<EngineTypeInitialiser>(\n\t\t\t\tmodule,\n\t\t\t\tmethod\n\t\t\t);\n\n\t\t\tfor (let i = 0; i < typeConfig.length; i++) {\n\t\t\t\tawait this.logInfo(\n\t\t\t\t\tI18n.formatMessage(\"engineCore.configuring\", {\n\t\t\t\t\t\tcomponentType: typeKey,\n\t\t\t\t\t\tconfigType: typeConfig[i].type\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\tconst result = await instanceMethod(this, this._context, typeConfig[i]);\n\n\t\t\t\tif (Is.stringValue(result.instanceType) && Is.object(result.component)) {\n\t\t\t\t\tconst finalInstanceType = typeConfig[i].overrideInstanceType ?? result.instanceType;\n\t\t\t\t\tthis._context.componentInstances.push({\n\t\t\t\t\t\tinstanceType: finalInstanceType,\n\t\t\t\t\t\tcomponent: result.component\n\t\t\t\t\t});\n\n\t\t\t\t\tresult.factory?.register(finalInstanceType, () => result.component);\n\n\t\t\t\t\tthis._context.registeredInstances[typeKey] ??= [];\n\n\t\t\t\t\tthis._context.registeredInstances[typeKey].push({\n\t\t\t\t\t\ttype: finalInstanceType,\n\t\t\t\t\t\tisDefault: typeConfig[i].isDefault,\n\t\t\t\t\t\tfeatures: typeConfig[i].features\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tthrow new GeneralError(\"engineCore\", \"componentUnknownType\", {\n\t\t\t\t\t\ttype: typeConfig[i].type,\n\t\t\t\t\t\tcomponentType: typeKey\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Setup the engine logger.\n\t * @internal\n\t */\n\tprivate setupEngineLogger(): void {\n\t\tconst silent = this._context.config.silent ?? false;\n\t\tconst engineLoggerConnector = silent\n\t\t\t? new SilentLoggingConnector()\n\t\t\t: new ConsoleLoggingConnector({\n\t\t\t\t\tconfig: {\n\t\t\t\t\t\ttranslateMessages: true,\n\t\t\t\t\t\thideGroups: true\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\tthis._context.componentInstances.push({\n\t\t\tinstanceType: EngineCore.LOGGING_CONNECTOR_TYPE_NAME,\n\t\t\tcomponent: engineLoggerConnector\n\t\t});\n\n\t\tLoggingConnectorFactory.register(\n\t\t\tEngineCore.LOGGING_CONNECTOR_TYPE_NAME,\n\t\t\t() => engineLoggerConnector\n\t\t);\n\n\t\tthis._context.registeredInstances.loggingConnector = [\n\t\t\t{\n\t\t\t\ttype: EngineCore.LOGGING_CONNECTOR_TYPE_NAME\n\t\t\t}\n\t\t];\n\n\t\tconst engineLoggerComponent = new LoggingService({\n\t\t\tloggingConnectorType: EngineCore.LOGGING_CONNECTOR_TYPE_NAME\n\t\t});\n\t\tthis._engineLoggingComponent = engineLoggerComponent;\n\n\t\tComponentFactory.register(EngineCore.LOGGING_COMPONENT_TYPE_NAME, () => engineLoggerComponent);\n\t\tthis._context.registeredInstances.loggingComponent = [\n\t\t\t{\n\t\t\t\ttype: EngineCore.LOGGING_COMPONENT_TYPE_NAME\n\t\t\t}\n\t\t];\n\t}\n\n\t/**\n\t * Load the state.\n\t * @returns True if the state was loaded and can continue.\n\t * @internal\n\t */\n\tprivate async stateLoad(): Promise<boolean> {\n\t\tif (this._stateStorage) {\n\t\t\ttry {\n\t\t\t\tthis._context.state = ((await this._stateStorage.load(this)) ?? {}) as S;\n\t\t\t\tthis._context.stateDirty = false;\n\n\t\t\t\treturn true;\n\t\t\t} catch (err) {\n\t\t\t\tawait this.logError(BaseError.fromError(err));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Save the state.\n\t * @returns True if the state was saved.\n\t * @internal\n\t */\n\tprivate async stateSave(): Promise<boolean> {\n\t\tif (this._stateStorage && !Is.empty(this._context.state) && this._context.stateDirty) {\n\t\t\ttry {\n\t\t\t\tawait this._stateStorage.save(this, this._context.state);\n\t\t\t\tthis._context.stateDirty = false;\n\t\t\t\treturn true;\n\t\t\t} catch (err) {\n\t\t\t\tawait this.logError(BaseError.fromError(err));\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Bootstrap the engine.\n\t * @internal\n\t */\n\tprivate async bootstrap(): Promise<void> {\n\t\tif (!this._skipBootstrap) {\n\t\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.bootstrapStarted`));\n\n\t\t\t// First bootstrap the components.\n\t\t\tfor (const instance of this._context.componentInstances) {\n\t\t\t\tconst bootstrapMethod = instance.component.bootstrap?.bind(instance.component);\n\t\t\t\tif (Is.function(bootstrapMethod)) {\n\t\t\t\t\tawait this.logInfo(\n\t\t\t\t\t\tI18n.formatMessage(`${nameofCamelCase<EngineCore>()}.bootstrapping`, {\n\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\n\t\t\t\t\tconst bootstrapSuccess = await bootstrapMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);\n\n\t\t\t\t\t// If the bootstrap method failed then throw an error\n\t\t\t\t\tif (!bootstrapSuccess) {\n\t\t\t\t\t\tthrow new GeneralError(EngineCore.CLASS_NAME, \"bootstrapFailed\", {\n\t\t\t\t\t\t\tclassName: instance.component.className(),\n\t\t\t\t\t\t\tinstanceType: instance.instanceType\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Now perform any custom bootstrap operations\n\t\t\tconst customBootstrap = this._customBootstrap;\n\t\t\tif (Is.function(customBootstrap)) {\n\t\t\t\tawait customBootstrap.call(this, this, this._context);\n\t\t\t}\n\n\t\t\tawait this.logInfo(I18n.formatMessage(`${nameofCamelCase<EngineCore>()}.bootstrapComplete`));\n\t\t}\n\t}\n}\n"]}
|
package/dist/es/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Copyright 2024 IOTA Stiftung.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
+
export * from "./engineCore.js";
|
|
4
|
+
export * from "./models/IEngineCoreOptions.js";
|
|
5
|
+
export * from "./storage/fileStateStorage.js";
|
|
6
|
+
export * from "./storage/memoryStateStorage.js";
|
|
7
|
+
export * from "./utils/engineModuleHelper.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./engineCore.js\";\nexport * from \"./models/IEngineCoreOptions.js\";\nexport * from \"./storage/fileStateStorage.js\";\nexport * from \"./storage/memoryStateStorage.js\";\nexport * from \"./utils/engineModuleHelper.js\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IEngineCoreOptions.js","sourceRoot":"","sources":["../../../src/models/IEngineCoreOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIEngineCore,\n\tIEngineCoreConfig,\n\tIEngineCoreContext,\n\tIEngineState,\n\tIEngineStateStorage\n} from \"@twin.org/engine-models\";\n\n/**\n * The options for creating engine core.\n */\nexport interface IEngineCoreOptions<\n\tC extends IEngineCoreConfig = IEngineCoreConfig,\n\tS extends IEngineState = IEngineState\n> {\n\t/**\n\t * The engine core config.\n\t */\n\tconfig?: C;\n\n\t/**\n\t * The state storage component.\n\t */\n\tstateStorage?: IEngineStateStorage<S>;\n\n\t/**\n\t * Skip the bootstrap process, useful for additional engine instances.\n\t */\n\tskipBootstrap?: boolean;\n\n\t/**\n\t * Populate the type initialisers for the engine.\n\t */\n\tpopulateTypeInitialisers?: (\n\t\tengineCore: IEngineCore<C, S>,\n\t\tcontext: IEngineCoreContext<C, S>\n\t) => void;\n\n\t/**\n\t * Custom bootstrap method for the engine.\n\t */\n\tcustomBootstrap?: (\n\t\tengineCore: IEngineCore<C, S>,\n\t\tcontext: IEngineCoreContext<C, S>\n\t) => Promise<void>;\n}\n"]}
|