@twin.org/engine-core 0.0.2-next.9 → 0.0.3-next.2

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.
@@ -1,91 +1,42 @@
1
- import { isMainThread } from 'node:worker_threads';
2
- import { I18n, StringHelper, Is, BaseError, GeneralError, ErrorHelper, Guards, 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
- 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(`${StringHelper.camelCase(this.CLASS_NAME)}.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(`${StringHelper.camelCase(this.CLASS_NAME)}.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
- * Name for the engine logger.
17
+ * Name for the engine logger component, used for direct console logging.
73
18
  */
74
- static LOGGER_TYPE_NAME = "engine";
19
+ static LOGGING_COMPONENT_TYPE_NAME = "engine-logging-service";
75
20
  /**
76
- * Runtime name for the class in camel case.
77
- * @internal
21
+ * Name for the engine logger connector, used for direct console logging.
78
22
  */
79
- static _CLASS_NAME_CAMEL_CASE = StringHelper.camelCase("EngineCore");
23
+ static LOGGING_CONNECTOR_TYPE_NAME = "engine-logging-connector";
80
24
  /**
81
25
  * Runtime name for the class.
82
- * @internal
83
26
  */
84
- static _CLASS_NAME = "EngineCore";
27
+ static CLASS_NAME = "EngineCore";
85
28
  /**
86
29
  * The core context.
87
30
  */
88
31
  _context;
32
+ /**
33
+ * The context ID keys.
34
+ */
35
+ _contextIdKeys;
36
+ /**
37
+ * The context IDs.
38
+ */
39
+ _contextIds;
89
40
  /**
90
41
  * The state storage interface.
91
42
  * @internal
@@ -101,11 +52,6 @@ class EngineCore {
101
52
  * @internal
102
53
  */
103
54
  _skipBootstrap;
104
- /**
105
- * The logger type name to use.
106
- * @internal
107
- */
108
- _loggerTypeName;
109
55
  /**
110
56
  * The type initialisers.
111
57
  * @internal
@@ -144,8 +90,8 @@ class EngineCore {
144
90
  this._skipBootstrap = options.skipBootstrap ?? false;
145
91
  this._populateTypeInitialisers = options.populateTypeInitialisers;
146
92
  this._customBootstrap = options.customBootstrap;
147
- this._loggerTypeName = options.loggerTypeName ?? EngineCore.LOGGER_TYPE_NAME;
148
93
  this._typeInitialisers = [];
94
+ this._contextIdKeys = [];
149
95
  this._context = {
150
96
  config: options.config,
151
97
  registeredInstances: {},
@@ -163,20 +109,67 @@ class EngineCore {
163
109
  /**
164
110
  * Add a type initialiser.
165
111
  * @param type The type to add the initialiser for.
166
- * @param typeConfig The type config.
167
112
  * @param module The name of the module which contains the initialiser method.
168
113
  * @param method The name of the method to call.
169
114
  */
170
- addTypeInitialiser(type, typeConfig, module, method) {
171
- if (!Is.empty(typeConfig)) {
115
+ addTypeInitialiser(type, module, method) {
116
+ Guards.stringValue(EngineCore.CLASS_NAME, "type", type);
117
+ Guards.stringValue(EngineCore.CLASS_NAME, "module", module);
118
+ Guards.stringValue(EngineCore.CLASS_NAME, "method", method);
119
+ const currentIndex = this._typeInitialisers.findIndex(t => t.type === type);
120
+ if (currentIndex >= 0) {
121
+ this._typeInitialisers[currentIndex].module = module;
122
+ this._typeInitialisers[currentIndex].method = method;
123
+ }
124
+ else {
172
125
  this._typeInitialisers.push({
173
126
  type,
174
- typeConfig,
175
127
  module,
176
128
  method
177
129
  });
178
130
  }
179
131
  }
132
+ /**
133
+ * Get the type config for a specific type.
134
+ * @param type The type to get the config for.
135
+ * @returns The type config or undefined if not found.
136
+ */
137
+ getTypeConfig(type) {
138
+ Guards.stringValue(EngineCore.CLASS_NAME, "type", type);
139
+ return this._context.config.types?.[type];
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
+ }
180
173
  /**
181
174
  * Start the engine core.
182
175
  * @returns True if the start was successful.
@@ -186,41 +179,60 @@ class EngineCore {
186
179
  return false;
187
180
  }
188
181
  this.setupEngineLogger();
189
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.starting`));
182
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.starting`));
190
183
  if (this._context.config.debug) {
191
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.debuggingEnabled`));
184
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.debuggingEnabled`));
192
185
  }
193
186
  let canContinue;
194
187
  try {
195
188
  canContinue = await this.stateLoad();
196
189
  if (canContinue) {
197
- for (const { type, typeConfig, module, method } of this._typeInitialisers) {
198
- await this.initialiseTypeConfig(type, typeConfig, module, method);
190
+ for (const { type, module, method } of this._typeInitialisers) {
191
+ await this.initialiseTypeConfig(type, module, method);
199
192
  }
200
193
  await this.bootstrap();
201
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStarting`));
202
- for (const instance of this._context.componentInstances) {
203
- if (Is.function(instance.component.start)) {
204
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStarting`, {
205
- element: instance.instanceType
206
- }));
207
- await instance.component.start(this._context.state.nodeIdentity, this._loggerTypeName);
194
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStarting`));
195
+ await ContextIdStore.run(this._contextIds ?? {}, async () => {
196
+ for (const instance of this._context.componentInstances) {
197
+ if (!instance.started) {
198
+ const startMethod = instance.component.start?.bind(instance.component);
199
+ if (Is.function(startMethod)) {
200
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentStarting`, {
201
+ className: instance.component.className(),
202
+ instanceType: instance.instanceType
203
+ }));
204
+ try {
205
+ await startMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
206
+ instance.started = true;
207
+ }
208
+ catch (err) {
209
+ await this.logError(new GeneralError(EngineCore.CLASS_NAME, "componentStartFailed", {
210
+ className: instance.component.className(),
211
+ instanceType: instance.instanceType
212
+ }, BaseError.fromError(err)));
213
+ throw err;
214
+ }
215
+ }
216
+ }
208
217
  }
209
- }
210
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsComplete`));
218
+ });
219
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsComplete`));
211
220
  }
212
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.started`));
221
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.started`));
213
222
  this._isStarted = true;
214
223
  }
215
224
  catch (err) {
216
225
  canContinue = false;
217
- this.logError(BaseError.fromError(err));
226
+ await this.logError(BaseError.fromError(err));
218
227
  }
219
228
  finally {
220
229
  if (!(await this.stateSave())) {
221
230
  canContinue = false;
222
231
  }
223
232
  }
233
+ if (!canContinue) {
234
+ await this.stop();
235
+ }
224
236
  return canContinue;
225
237
  }
226
238
  /**
@@ -228,26 +240,34 @@ class EngineCore {
228
240
  * @returns Nothing.
229
241
  */
230
242
  async stop() {
231
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopping`));
232
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopping`));
233
- for (const instance of this._context.componentInstances) {
234
- if (Is.function(instance.component.stop)) {
235
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentStopping`, {
236
- element: instance.instanceType
237
- }));
238
- try {
239
- await instance.component.stop(this._context.state.nodeIdentity, this._loggerTypeName);
240
- }
241
- catch (err) {
242
- this.logError(new GeneralError(EngineCore._CLASS_NAME, "componentStopFailed", {
243
- component: instance.instanceType
244
- }, BaseError.fromError(err)));
243
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.stopping`));
244
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopping`));
245
+ await ContextIdStore.run(this._contextIds ?? {}, async () => {
246
+ for (const instance of this._context.componentInstances) {
247
+ if (instance.started) {
248
+ instance.started = false;
249
+ const stopMethod = instance.component.stop?.bind(instance.component);
250
+ if (Is.function(stopMethod)) {
251
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentStopping`, {
252
+ className: instance.component.className(),
253
+ instanceType: instance.instanceType
254
+ }));
255
+ try {
256
+ await stopMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
257
+ }
258
+ catch (err) {
259
+ await this.logError(new GeneralError(EngineCore.CLASS_NAME, "componentStopFailed", {
260
+ className: instance.component.className(),
261
+ instanceType: instance.instanceType
262
+ }, BaseError.fromError(err)));
263
+ }
264
+ }
245
265
  }
246
266
  }
247
- }
267
+ });
248
268
  await this.stateSave();
249
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.componentsStopped`));
250
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.stopped`));
269
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.componentsStopped`));
270
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.stopped`));
251
271
  }
252
272
  /**
253
273
  * Is the engine started.
@@ -274,9 +294,9 @@ class EngineCore {
274
294
  * Log info.
275
295
  * @param message The message to log.
276
296
  */
277
- logInfo(message) {
278
- this._engineLoggingComponent?.log({
279
- source: EngineCore._CLASS_NAME,
297
+ async logInfo(message) {
298
+ await this._engineLoggingComponent?.log({
299
+ source: EngineCore.CLASS_NAME,
280
300
  level: "info",
281
301
  message
282
302
  });
@@ -285,7 +305,7 @@ class EngineCore {
285
305
  * Log error.
286
306
  * @param error The error to log.
287
307
  */
288
- logError(error) {
308
+ async logError(error) {
289
309
  const formattedErrors = ErrorHelper.localizeErrors(error);
290
310
  for (const formattedError of formattedErrors) {
291
311
  let message = Is.stringValue(formattedError.source)
@@ -294,8 +314,8 @@ class EngineCore {
294
314
  if (this._context.config.debug && Is.stringValue(formattedError.stack)) {
295
315
  message += `\n${formattedError.stack}`;
296
316
  }
297
- this._engineLoggingComponent?.log({
298
- source: EngineCore._CLASS_NAME,
317
+ await this._engineLoggingComponent?.log({
318
+ source: EngineCore.CLASS_NAME,
299
319
  level: "error",
300
320
  message
301
321
  });
@@ -330,10 +350,10 @@ class EngineCore {
330
350
  * @throws If a matching instance was not found.
331
351
  */
332
352
  getRegisteredInstanceType(componentConnectorType, features) {
333
- Guards.stringValue(EngineCore._CLASS_NAME, "componentConnectorType", componentConnectorType);
353
+ Guards.stringValue(EngineCore.CLASS_NAME, "componentConnectorType", componentConnectorType);
334
354
  const registeredType = this.getRegisteredInstanceTypeOptional(componentConnectorType, features);
335
355
  if (!Is.stringValue(registeredType)) {
336
- throw new GeneralError(EngineCore._CLASS_NAME, "instanceTypeNotFound", {
356
+ throw new GeneralError(EngineCore.CLASS_NAME, "instanceTypeNotFound", {
337
357
  type: componentConnectorType,
338
358
  features: (features ?? ["default"]).join(",")
339
359
  });
@@ -354,7 +374,12 @@ class EngineCore {
354
374
  registeredType = registeredTypes.find(t => t.features?.every(f => features.includes(f)))?.type;
355
375
  }
356
376
  else {
357
- registeredType = registeredTypes[0]?.type;
377
+ // First look for the default entry
378
+ registeredType = registeredTypes.find(t => t.isDefault)?.type;
379
+ // Can't find a default so just use the first entry
380
+ if (!Is.stringValue(registeredType)) {
381
+ registeredType = registeredTypes[0]?.type;
382
+ }
358
383
  }
359
384
  }
360
385
  return registeredType;
@@ -374,7 +399,7 @@ class EngineCore {
374
399
  state: this._context.state,
375
400
  typeInitialisers: this._typeInitialisers,
376
401
  entitySchemas,
377
- loggerTypeName: this._loggerTypeName
402
+ contextIdKeys: this._contextIdKeys
378
403
  };
379
404
  return cloneData;
380
405
  }
@@ -384,11 +409,10 @@ class EngineCore {
384
409
  * @param silent Should the clone be silent.
385
410
  */
386
411
  populateClone(cloneData, silent) {
387
- Guards.object(EngineCore._CLASS_NAME, "cloneData", cloneData);
388
- Guards.object(EngineCore._CLASS_NAME, "cloneData.config", cloneData.config);
389
- Guards.object(EngineCore._CLASS_NAME, "cloneData.state", cloneData.state);
390
- Guards.array(EngineCore._CLASS_NAME, "cloneData.typeInitialisers", cloneData.typeInitialisers);
391
- this._loggerTypeName = cloneData.loggerTypeName;
412
+ Guards.object(EngineCore.CLASS_NAME, "cloneData", cloneData);
413
+ Guards.object(EngineCore.CLASS_NAME, "cloneData.config", cloneData.config);
414
+ Guards.object(EngineCore.CLASS_NAME, "cloneData.state", cloneData.state);
415
+ Guards.array(EngineCore.CLASS_NAME, "cloneData.typeInitialisers", cloneData.typeInitialisers);
392
416
  this._skipBootstrap = true;
393
417
  this._isClone = true;
394
418
  if (silent ?? false) {
@@ -402,6 +426,7 @@ class EngineCore {
402
426
  stateDirty: false
403
427
  };
404
428
  this._typeInitialisers = cloneData.typeInitialisers;
429
+ this._contextIdKeys.push(...cloneData.contextIdKeys);
405
430
  for (const schemaName of Object.keys(cloneData.entitySchemas)) {
406
431
  EntitySchemaFactory.register(schemaName, () => cloneData.entitySchemas[schemaName]);
407
432
  }
@@ -414,25 +439,36 @@ class EngineCore {
414
439
  * @param instanceMethod The function to initialise the instance.
415
440
  * @internal
416
441
  */
417
- async initialiseTypeConfig(typeKey, typeConfig, module, method) {
442
+ async initialiseTypeConfig(typeKey, module, method) {
443
+ const typeConfig = this._context.config.types?.[typeKey];
418
444
  if (Is.arrayValue(typeConfig)) {
419
445
  const instanceMethod = await ModuleHelper.getModuleEntry(module, method);
420
446
  for (let i = 0; i < typeConfig.length; i++) {
421
- const instanceType = instanceMethod(this, this._context, typeConfig[i], typeConfig[i].overrideInstanceType);
422
- if (Is.stringValue(instanceType)) {
447
+ await this.logInfo(I18n.formatMessage("engineCore.configuring", {
448
+ componentType: typeKey,
449
+ configType: typeConfig[i].type
450
+ }));
451
+ const result = await instanceMethod(this, this._context, typeConfig[i]);
452
+ if (Is.stringValue(result.instanceType) && Is.object(result.component)) {
453
+ const finalInstanceType = typeConfig[i].overrideInstanceType ?? result.instanceType;
454
+ this._context.componentInstances.push({
455
+ instanceType: finalInstanceType,
456
+ component: result.component,
457
+ started: false
458
+ });
459
+ result.factory?.register(finalInstanceType, () => result.component);
423
460
  this._context.registeredInstances[typeKey] ??= [];
424
- if (typeConfig[i].isDefault ?? false) {
425
- this._context.registeredInstances[typeKey].unshift({
426
- type: instanceType,
427
- features: typeConfig[i].features
428
- });
429
- }
430
- else {
431
- this._context.registeredInstances[typeKey].push({
432
- type: instanceType,
433
- features: typeConfig[i].features
434
- });
435
- }
461
+ this._context.registeredInstances[typeKey].push({
462
+ type: finalInstanceType,
463
+ isDefault: typeConfig[i].isDefault,
464
+ features: typeConfig[i].features
465
+ });
466
+ }
467
+ else {
468
+ throw new GeneralError("engineCore", "componentUnknownType", {
469
+ type: typeConfig[i].type,
470
+ componentType: typeKey
471
+ });
436
472
  }
437
473
  }
438
474
  }
@@ -452,23 +488,24 @@ class EngineCore {
452
488
  }
453
489
  });
454
490
  this._context.componentInstances.push({
455
- instanceType: this._loggerTypeName,
456
- component: engineLoggerConnector
491
+ instanceType: EngineCore.LOGGING_CONNECTOR_TYPE_NAME,
492
+ component: engineLoggerConnector,
493
+ started: false
457
494
  });
458
- LoggingConnectorFactory.register(this._loggerTypeName, () => engineLoggerConnector);
495
+ LoggingConnectorFactory.register(EngineCore.LOGGING_CONNECTOR_TYPE_NAME, () => engineLoggerConnector);
459
496
  this._context.registeredInstances.loggingConnector = [
460
497
  {
461
- type: this._loggerTypeName
498
+ type: EngineCore.LOGGING_CONNECTOR_TYPE_NAME
462
499
  }
463
500
  ];
464
501
  const engineLoggerComponent = new LoggingService({
465
- loggingConnectorType: this._loggerTypeName
502
+ loggingConnectorType: EngineCore.LOGGING_CONNECTOR_TYPE_NAME
466
503
  });
467
504
  this._engineLoggingComponent = engineLoggerComponent;
468
- ComponentFactory.register("logging-service", () => engineLoggerComponent);
505
+ ComponentFactory.register(EngineCore.LOGGING_COMPONENT_TYPE_NAME, () => engineLoggerComponent);
469
506
  this._context.registeredInstances.loggingComponent = [
470
507
  {
471
- type: "logging-service"
508
+ type: EngineCore.LOGGING_COMPONENT_TYPE_NAME
472
509
  }
473
510
  ];
474
511
  }
@@ -485,7 +522,7 @@ class EngineCore {
485
522
  return true;
486
523
  }
487
524
  catch (err) {
488
- this.logError(BaseError.fromError(err));
525
+ await this.logError(BaseError.fromError(err));
489
526
  return false;
490
527
  }
491
528
  }
@@ -504,7 +541,7 @@ class EngineCore {
504
541
  return true;
505
542
  }
506
543
  catch (err) {
507
- this.logError(BaseError.fromError(err));
544
+ await this.logError(BaseError.fromError(err));
508
545
  }
509
546
  return false;
510
547
  }
@@ -516,130 +553,32 @@ class EngineCore {
516
553
  */
517
554
  async bootstrap() {
518
555
  if (!this._skipBootstrap) {
519
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapStarted`));
556
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapStarted`));
520
557
  // First bootstrap the components.
521
558
  for (const instance of this._context.componentInstances) {
522
- if (Is.function(instance.component.bootstrap)) {
523
- const instanceName = this.getInstanceName(instance);
524
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapping`, {
525
- element: instanceName
559
+ const bootstrapMethod = instance.component.bootstrap?.bind(instance.component);
560
+ if (Is.function(bootstrapMethod)) {
561
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapping`, {
562
+ className: instance.component.className(),
563
+ instanceType: instance.instanceType
526
564
  }));
527
- const bootstrapSuccess = await instance.component.bootstrap(this._loggerTypeName);
565
+ const bootstrapSuccess = await bootstrapMethod(EngineCore.LOGGING_COMPONENT_TYPE_NAME);
528
566
  // If the bootstrap method failed then throw an error
529
567
  if (!bootstrapSuccess) {
530
- throw new GeneralError(EngineCore._CLASS_NAME, "bootstrapFailed", {
531
- component: `${instance.component.CLASS_NAME}:${instance.instanceType}`
568
+ throw new GeneralError(EngineCore.CLASS_NAME, "bootstrapFailed", {
569
+ className: instance.component.className(),
570
+ instanceType: instance.instanceType
532
571
  });
533
572
  }
534
573
  }
535
574
  }
536
575
  // Now perform any custom bootstrap operations
537
- if (Is.function(this._customBootstrap)) {
538
- await this._customBootstrap(this, this._context);
539
- }
540
- this.logInfo(I18n.formatMessage(`${EngineCore._CLASS_NAME_CAMEL_CASE}.bootstrapComplete`));
541
- }
542
- }
543
- /**
544
- * Get the instance name.
545
- * @param instance The instance to get the name for.
546
- * @param instance.instanceType The instance type.
547
- * @param instance.component The component.
548
- * @returns The instance name.
549
- * @internal
550
- */
551
- getInstanceName(instance) {
552
- return `${instance.component.CLASS_NAME}-${instance.instanceType}`;
553
- }
554
- }
555
-
556
- // Copyright 2024 IOTA Stiftung.
557
- // SPDX-License-Identifier: Apache-2.0.
558
- /**
559
- * Store state in a file.
560
- */
561
- class FileStateStorage {
562
- /**
563
- * Runtime name for the class.
564
- */
565
- CLASS_NAME = "FileStateStorage";
566
- /**
567
- * The filename to store the state.
568
- * @internal
569
- */
570
- _filename;
571
- /**
572
- * Readonly mode state file is not updated.
573
- * @internal
574
- */
575
- _readonlyMode;
576
- /**
577
- * Create a new instance of FileStateStorage.
578
- * @param filename The filename to store the state.
579
- * @param readonlyMode Whether the file is in read-only mode.
580
- */
581
- constructor(filename, readonlyMode = false) {
582
- Guards.stringValue(this.CLASS_NAME, "filename", filename);
583
- this._filename = filename;
584
- this._readonlyMode = readonlyMode;
585
- }
586
- /**
587
- * Method for loading the state.
588
- * @param engineCore The engine core to load the state for.
589
- * @returns The state of the engine or undefined if it doesn't exist.
590
- */
591
- async load(engineCore) {
592
- try {
593
- engineCore.logInfo(I18n.formatMessage(`${StringHelper.camelCase(this.CLASS_NAME)}.loading`, {
594
- filename: this._filename
595
- }));
596
- if (await this.fileExists(this._filename)) {
597
- const content = await readFile(this._filename, "utf8");
598
- return JSON.parse(content.toString());
576
+ const customBootstrap = this._customBootstrap;
577
+ if (Is.function(customBootstrap)) {
578
+ await customBootstrap.call(this, this, this._context);
599
579
  }
600
- }
601
- catch (err) {
602
- throw new GeneralError(this.CLASS_NAME, "loadingError", { filename: this._filename }, BaseError.fromError(err));
603
- }
604
- }
605
- /**
606
- * Method for saving the state.
607
- * @param engineCore The engine core to save the state for.
608
- * @param state The state of the engine to save.
609
- * @returns Nothing.
610
- */
611
- async save(engineCore, state) {
612
- if (!this._readonlyMode) {
613
- try {
614
- engineCore.logInfo(I18n.formatMessage(`${StringHelper.camelCase(this.CLASS_NAME)}.saving`, {
615
- filename: this._filename
616
- }));
617
- try {
618
- await mkdir(path.dirname(this._filename), { recursive: true });
619
- }
620
- catch { }
621
- await writeFile(this._filename, JSON.stringify(state, undefined, "\t"), "utf8");
622
- }
623
- catch (err) {
624
- throw new GeneralError(this.CLASS_NAME, "savingError", { filename: this._filename }, BaseError.fromError(err));
625
- }
626
- }
627
- }
628
- /**
629
- * Does the specified file exist.
630
- * @param filename The filename to check for existence.
631
- * @returns True if the file exists.
632
- * @internal
633
- */
634
- async fileExists(filename) {
635
- try {
636
- const stats = await stat(filename);
637
- return stats.isFile();
638
- }
639
- catch {
640
- return false;
580
+ await this.logInfo(I18n.formatMessage(`${"engineCore"}.bootstrapComplete`));
641
581
  }
642
582
  }
643
583
  }
644
-
645
- export { EngineCore, FileStateStorage, MemoryStateStorage };
584
+ //# sourceMappingURL=engineCore.js.map