@ti-engine/core 1.1.4 → 1.1.8

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,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
2
+ * The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
3
+ * Copyright © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
+ */
5
8
 
6
9
  const MessageObserver = require( "#message-observer" );
7
10
  const _ = require( "lodash" );
@@ -92,7 +95,9 @@ class MessageExchange extends MessageObserver {
92
95
  * @returns {string}
93
96
  * @public
94
97
  */
95
- static get connectionNameRequestsOut() { return this.#connectionNameRequestsOut; }
98
+ static get connectionNameRequestsOut() {
99
+ return this.#connectionNameRequestsOut;
100
+ }
96
101
 
97
102
  /**
98
103
  * Used to set the connection name for the outgoing message requests.
@@ -101,7 +106,9 @@ class MessageExchange extends MessageObserver {
101
106
  * @param {string} value
102
107
  * @public
103
108
  */
104
- static set connectionNameRequestsOut( value ) { this.#connectionNameRequestsOut = value; }
109
+ static set connectionNameRequestsOut( value ) {
110
+ this.#connectionNameRequestsOut = value;
111
+ }
105
112
 
106
113
  /**
107
114
  * Property returning the configured connection name for the incoming message requests.
@@ -110,7 +117,9 @@ class MessageExchange extends MessageObserver {
110
117
  * @returns {string}
111
118
  * @public
112
119
  */
113
- static get connectionNameRequestsIn() { return this.#connectionNameRequestsIn; }
120
+ static get connectionNameRequestsIn() {
121
+ return this.#connectionNameRequestsIn;
122
+ }
114
123
 
115
124
  /**
116
125
  * Used to set the connection name for the incoming message requests.
@@ -119,7 +128,9 @@ class MessageExchange extends MessageObserver {
119
128
  * @param {string} value
120
129
  * @public
121
130
  */
122
- static set connectionNameRequestsIn( value ) { this.#connectionNameRequestsIn = value; }
131
+ static set connectionNameRequestsIn( value ) {
132
+ this.#connectionNameRequestsIn = value;
133
+ }
123
134
 
124
135
  /**
125
136
  * Property returning the configured connection name for the outgoing message responses.
@@ -128,7 +139,9 @@ class MessageExchange extends MessageObserver {
128
139
  * @returns {string}
129
140
  * @public
130
141
  */
131
- static get connectionNameResponsesOut() { return this.#connectionNameResponsesOut; }
142
+ static get connectionNameResponsesOut() {
143
+ return this.#connectionNameResponsesOut;
144
+ }
132
145
 
133
146
  /**
134
147
  * Used to set the connection name for the outgoing message responses.
@@ -137,7 +150,9 @@ class MessageExchange extends MessageObserver {
137
150
  * @param {string} value
138
151
  * @public
139
152
  */
140
- static set connectionNameResponsesOut( value ) { this.#connectionNameResponsesOut = value; }
153
+ static set connectionNameResponsesOut( value ) {
154
+ this.#connectionNameResponsesOut = value;
155
+ }
141
156
 
142
157
  /**
143
158
  * Property returning the configured connection name for the incoming message responses.
@@ -146,7 +161,9 @@ class MessageExchange extends MessageObserver {
146
161
  * @returns {string}
147
162
  * @public
148
163
  */
149
- static get connectionNameResponsesIn() { return this.#connectionNameResponsesIn; }
164
+ static get connectionNameResponsesIn() {
165
+ return this.#connectionNameResponsesIn;
166
+ }
150
167
 
151
168
  /**
152
169
  * Used to set the connection name for the incoming message responses.
@@ -155,7 +172,9 @@ class MessageExchange extends MessageObserver {
155
172
  * @param {string} value
156
173
  * @public
157
174
  */
158
- static set connectionNameResponsesIn( value ) { this.#connectionNameResponsesIn = value; }
175
+ static set connectionNameResponsesIn( value ) {
176
+ this.#connectionNameResponsesIn = value;
177
+ }
159
178
 
160
179
  /**
161
180
  * Property returning the identifier of the pending messages queue.
@@ -164,7 +183,9 @@ class MessageExchange extends MessageObserver {
164
183
  * @returns {string}
165
184
  * @public
166
185
  */
167
- static get pendingQueue() { return "pending:"; }
186
+ static get pendingQueue() {
187
+ return "pending:";
188
+ }
168
189
 
169
190
  /**
170
191
  * Property returning the identifier of the processed messages queue.
@@ -173,7 +194,9 @@ class MessageExchange extends MessageObserver {
173
194
  * @returns {string}
174
195
  * @public
175
196
  */
176
- static get processedQueue() { return "processed:"; }
197
+ static get processedQueue() {
198
+ return "processed:";
199
+ }
177
200
 
178
201
  /**
179
202
  * Property returning the configured service instance ID.
@@ -182,7 +205,9 @@ class MessageExchange extends MessageObserver {
182
205
  * @returns {string}
183
206
  * @public
184
207
  */
185
- get instanceID() { return this.#instanceID; }
208
+ get instanceID() {
209
+ return this.#instanceID;
210
+ }
186
211
 
187
212
  /**
188
213
  * Property returning the configured service domain name.
@@ -191,7 +216,9 @@ class MessageExchange extends MessageObserver {
191
216
  * @returns {string}
192
217
  * @public
193
218
  */
194
- get serviceDomainName() { return this.#serviceDomainName; }
219
+ get serviceDomainName() {
220
+ return this.#serviceDomainName;
221
+ }
195
222
 
196
223
  /**
197
224
  * Returns the currently configured {@link MessageSender} for outbound message requests.
@@ -200,7 +227,9 @@ class MessageExchange extends MessageObserver {
200
227
  * @returns {MessageSender}
201
228
  * @public
202
229
  */
203
- get messageRequestsOut() { return this.#messageRequestsOut; }
230
+ get messageRequestsOut() {
231
+ return this.#messageRequestsOut;
232
+ }
204
233
 
205
234
  /**
206
235
  * Returns the currently configured {@link MessageSender} for outbound message responses.
@@ -209,7 +238,9 @@ class MessageExchange extends MessageObserver {
209
238
  * @returns {MessageSender}
210
239
  * @public
211
240
  */
212
- get messageResponsesOut() { return this.#messageResponsesOut; }
241
+ get messageResponsesOut() {
242
+ return this.#messageResponsesOut;
243
+ }
213
244
 
214
245
  /**
215
246
  * Returns the currently configured {@link MessageReceiver} for inbound message requests.
@@ -218,7 +249,9 @@ class MessageExchange extends MessageObserver {
218
249
  * @returns {MessageReceiver}
219
250
  * @public
220
251
  */
221
- get messageRequestsIn() { return this.#messageRequestsIn; }
252
+ get messageRequestsIn() {
253
+ return this.#messageRequestsIn;
254
+ }
222
255
 
223
256
  /**
224
257
  * Returns the currently configured {@link MessageReceiver} for inbound message responses.
@@ -227,7 +260,9 @@ class MessageExchange extends MessageObserver {
227
260
  * @returns {MessageReceiver}
228
261
  * @public
229
262
  */
230
- get messageResponsesIn() { return this.#messageResponsesIn; }
263
+ get messageResponsesIn() {
264
+ return this.#messageResponsesIn;
265
+ }
231
266
 
232
267
  /**
233
268
  * Returns a flag indicating if the message exchange is configured for outbound communication.
@@ -236,7 +271,9 @@ class MessageExchange extends MessageObserver {
236
271
  * @returns {boolean}
237
272
  * @public
238
273
  */
239
- get configuredOutbound() { return this.#configuredOutbound; }
274
+ get configuredOutbound() {
275
+ return this.#configuredOutbound;
276
+ }
240
277
 
241
278
  /**
242
279
  * Returns a flag indicating if the message exchange is configured for inbound communication.
@@ -245,7 +282,9 @@ class MessageExchange extends MessageObserver {
245
282
  * @returns {boolean}
246
283
  * @public
247
284
  */
248
- get configuredInbound() { return this.#configuredInbound; }
285
+ get configuredInbound() {
286
+ return this.#configuredInbound;
287
+ }
249
288
 
250
289
  /**
251
290
  * Should be used to enable all communication channels for messaging.
@@ -253,8 +292,8 @@ class MessageExchange extends MessageObserver {
253
292
  * NOTE: Override this to implement messaging initialization.
254
293
  *
255
294
  * @method
256
- * @param {boolean} configureInbound If set to 'true' it tells the message exchange to setup inbound messaging.
257
- * @param {boolean} configureOutbound If set to 'true' it tells the message exchange to setup outbound messaging.
295
+ * @param {boolean} configureInbound If set to 'true' it tells the message exchange to set up inbound messaging.
296
+ * @param {boolean} configureOutbound If set to 'true' it tells the message exchange to set up outbound messaging.
258
297
  * @returns {Promise}
259
298
  * @abstract
260
299
  * @public
@@ -368,9 +407,9 @@ class MessageExchange extends MessageObserver {
368
407
  message.destination.instanceID = this.#instanceID;
369
408
 
370
409
  if ( MessageExchange.connectionNameRequestsIn === identifier ) {
371
- messageTracer.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.RECEIVED, messageTracer.messageState.PENDING );
410
+ messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_REQUEST, messageTracer.dispatchEvent.RECEIVED, messageTracer.messageState.PENDING );
372
411
  } else if ( MessageExchange.connectionNameResponsesIn === identifier ) {
373
- messageTracer.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.RECEIVED, messageTracer.messageState.PROCESSED );
412
+ messageTracer.instance.recordTraceEntry( message, messageTracer.messageType.MESSAGE_RESPONSE, messageTracer.dispatchEvent.RECEIVED, messageTracer.messageState.PROCESSED );
374
413
  }
375
414
  }
376
415
 
@@ -416,4 +455,4 @@ class MessageExchange extends MessageObserver {
416
455
 
417
456
  }
418
457
 
419
- module.exports = MessageExchange;
458
+ module.exports = MessageExchange;
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
2
+ * The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
3
+ * Copyright © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
+ */
5
8
 
6
9
  const ConnectionObserver = require( "#connection-observer" );
7
10
  const _ = require( "lodash" );
@@ -88,7 +91,7 @@ class MessageHandler extends ConnectionObserver {
88
91
  }
89
92
 
90
93
  /**
91
- * Used to shutdown and disable the communication behavior of the handler.
94
+ * Used to shut down and disable the communication behavior of the handler.
92
95
  * <br/>
93
96
  * NOTE: Override this to add functionality.
94
97
  *
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
2
+ * The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
3
+ * Copyright © 2021-2025 Boris Kostadinov <kostadinov.boris@gmail.com>
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
+ */
5
8
 
6
9
  const config = require( "#config" );
7
10
  const tools = require( "#tools" );
@@ -28,11 +31,25 @@ class MessageMemoryCache {
28
31
  let db = config.getSetting( config.setting.MEMORY_CACHE_REDIS_DB );
29
32
  let authKey = config.getSetting( config.setting.MEMORY_CACHE_AUTH_KEY );
30
33
  let user = config.getSetting( config.setting.MEMORY_CACHE_USER );
31
- this.#redisClient = redis.createRedisClient( identifier, host, port, authKey, user, db );
34
+ let retryMaxAttempts = config.getSetting( config.setting.MEMORY_CACHE_RETRY_MAX_ATTEMPTS );
35
+ let retryMaxInterval = config.getSetting( config.setting.MEMORY_CACHE_RETRY_MAX_INTERVAL );
36
+ this.#redisClient = redis.createRedisClient( identifier, host, port, authKey, user, db, retryMaxInterval, retryMaxAttempts );
32
37
  }
33
38
 
34
39
  /* Public interface */
35
40
 
41
+ /**
42
+ * Used to gracefully shut down the cache service.
43
+ *
44
+ * @method
45
+ * @param {number} [timeoutMs]
46
+ * @return {Promise}
47
+ * @public
48
+ */
49
+ shutDown( timeoutMs ) {
50
+ return this.#redisClient.shutDown( timeoutMs );
51
+ }
52
+
36
53
  /**
37
54
  * Used to register a new {@link ConnectionObserver} for events related to the Redis connection state.
38
55
  *
@@ -71,7 +88,7 @@ class MessageMemoryCache {
71
88
  * @method
72
89
  * @param {Object} payload
73
90
  * @param {string} storeLocation
74
- * @returns {Promise<string>} Will return an unique ID of the storage location for the payload.
91
+ * @returns {Promise<string>} Will return a unique ID of the storage location for the payload.
75
92
  * @public
76
93
  */
77
94
  storeMessagePayload( payload, storeLocation ) {
@@ -148,4 +165,4 @@ class MessageMemoryCache {
148
165
  */
149
166
  module.exports.create = ( identifier ) => {
150
167
  return Object.freeze( new MessageMemoryCache( identifier ) );
151
- };
168
+ };
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
2
+ * The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
3
+ * Copyright © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
+ */
5
8
 
6
9
  const ConnectionObserver = require( "#connection-observer" );
7
10
  const exceptions = require( "#exceptions" );
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
2
+ * The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
3
+ * Copyright © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
+ */
5
8
 
6
9
  const MessageHandler = require( "#message-handler" );
7
10
  const logger = require( "#logger" );
@@ -39,7 +42,7 @@ class MessageReceiver extends MessageHandler {
39
42
  /* Public interface */
40
43
 
41
44
  /**
42
- * Property returning the configured receive queue.
45
+ * Property returning the configured receiving queue.
43
46
  *
44
47
  * @property
45
48
  * @returns {string}
@@ -62,7 +65,7 @@ class MessageReceiver extends MessageHandler {
62
65
  }
63
66
 
64
67
  /**
65
- * Used to shutdown and disable the communication behavior of the handler.
68
+ * Used to shut down and disable the communication behavior of the handler.
66
69
  * <br/>
67
70
  * NOTE: Override this to add functionality.
68
71
  *
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
2
+ * The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
3
+ * Copyright © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
+ */
5
8
 
6
9
  const MessageHandler = require( "#message-handler" );
7
10
  const exceptions = require( "#exceptions" );
@@ -47,7 +50,7 @@ class MessageSender extends MessageHandler {
47
50
  }
48
51
 
49
52
  /**
50
- * Used to shutdown and disable the communication behavior of the handler.
53
+ * Used to shut down and disable the communication behavior of the handler.
51
54
  * <br/>
52
55
  * NOTE: Override this to add functionality.
53
56
  *
@@ -1,7 +1,10 @@
1
1
  /*
2
- * SPDX-FileCopyrightText: © 2021-2023 Boris Kostadinov <kostadinov.boris@gmail.com>
3
- * SPDX-License-Identifier: ICU
4
- */
2
+ * The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.
3
+ * Copyright © 2021-2025 Boris Kostadinov <kostadinov.boris@gmail.com>
4
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
6
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
+ */
5
8
 
6
9
  const _ = require( "lodash" );
7
10
  const tools = require( "#tools" );
@@ -79,103 +82,149 @@ let messageStateEnum = tools.enum( {
79
82
  module.exports.messageState = messageStateEnum;
80
83
 
81
84
  /**
82
- * Used to create a log entry from the trace entry.
83
- *
84
- * @method
85
- * @param {TiTraceEntry} traceEntry The trace entry to log.
86
- * @param {TiLogSeverity} severity The log entry severity.
87
- * @private
88
- */
89
- let createLogEntry = ( traceEntry, severity ) => {
90
- logger.log( formatLogEntry( traceEntry ), severity, traceEntry );
91
- };
92
-
93
- /**
94
- * Used to format trace entry into log-suitable string.
85
+ * Used for recording message trace entries.
95
86
  *
96
- * @method
97
- * @param {TiTraceEntry} traceEntry
98
- * @return {string} Prepared trace info.
99
- * @private
87
+ * @class MessageTracer
88
+ * @singleton
89
+ * @public
100
90
  */
101
- let formatLogEntry = ( traceEntry ) => {
102
- return `Message(${ traceEntry.chainID || traceEntry.messageID }) Trace: '${ traceEntry.messageType } ${ traceEntry.dispatchEvent } ${ traceEntry.messageState }' From: '${ traceEntry.fromAddress }' To: '${ traceEntry.toAddress }'`;
103
- };
91
+ class MessageTracer {
104
92
 
105
- /**
106
- * Used to obscure sensitive data in the message, remove the payload, and return a snapshot.
107
- *
108
- * @method
109
- * @param {Message} message
110
- * @returns {Message}
111
- * @private
112
- */
113
- let obscureSensitiveData = ( message ) => {
114
- /** @type Message */
115
- let messageSnapshot = tools.parseJSON( _.replace( tools.stringifyJSON( message ), /("\w*?pin\w*?"|"\w*?pass\w*?"|"\w*?otp\w*?"):"(.*?)"/gmi, "\"SENSITIVE_PROPERTY\":\"OBSCURED_BY_SYSTEM\"" ) );
116
- delete messageSnapshot.payload;
117
- return messageSnapshot;
118
- };
93
+ static #instance = null;
119
94
 
120
- /**
121
- * Used to create a trace entry for the provided {@link Message} and parameters.
122
- * <br/>
123
- * NOTE: By default all trace events are stored in the memory cache for further processing and analysis. The
124
- * location is configured in the MESSAGE_EXCHANGE_TRACE_REPOSITORY setting.
125
- * <br/>
126
- * NOTE: Trace events are logged with severity level NOTICE or ERROR for failed dispatches. They still might be
127
- * filtered out if the minimum log level setting is set too high.
128
- *
129
- * @method
130
- * @param {Message} message The message to trace.
131
- * @param {TiMessageType} messageType The type of the message.
132
- * @param {TiDispatchEvent} dispatchEvent The event in the dispatch system that triggered the trace entry.
133
- * @param {TiMessageState} messageState The state of the processing of the message.
134
- * @public
135
- */
136
- module.exports.recordTraceEntry = ( message, messageType, dispatchEvent, messageState ) => {
137
- // depending on whether the message comes as request or response, the from and to addresses will be opposite:
138
- let source = message.source.route + "." + message.source.instanceID;
139
- let destination = message.destination.route + ( ( message.destination.instanceID != null ) ? "." + message.destination.instanceID : "" );
140
- let messageSnapshot = obscureSensitiveData( message );
141
- delete messageSnapshot.chainID;
142
- delete messageSnapshot.messageID;
143
- let currentDate = new Date();
144
-
145
- /** @type TiTraceEntry */
146
- let traceEntry = {
147
- chainID: message.chainID,
148
- dispatchEvent: tools.getEnumName( dispatchEventEnum, dispatchEvent ),
149
- fromAddress: ( messageType === messageTypeEnum.MESSAGE_REQUEST ) ? source : destination,
150
- messageID: message.messageID,
151
- messageSnapshot: messageSnapshot,
152
- messageState: tools.getEnumName( messageStateEnum, messageState ),
153
- messageType: tools.getEnumName( messageTypeEnum, messageType ),
154
- toAddress: ( messageType === messageTypeEnum.MESSAGE_REQUEST ) ? destination : source,
155
- traceTimestamp: currentDate.getTime(),
156
- traceID: tools.getUUID()
157
- };
158
-
159
- // only write the trace in the general log if this is enabled:
160
- if ( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_LOG_ENABLED ) === true ) {
161
- createLogEntry( traceEntry, ( dispatchEvent === dispatchEventEnum.FAILED ) ? logger.logSeverity.ERROR : logger.logSeverity.NOTICE );
95
+ /**
96
+ * @constructor
97
+ * @return {MessageTracer}
98
+ */
99
+ constructor() {
100
+ if ( !MessageTracer.#instance ) {
101
+ MessageTracer.#instance = this;
102
+ }
103
+ return MessageTracer.#instance;
162
104
  }
163
105
 
164
- // add the trace entry to the repository in the memory cache:
165
- cache.setJSON( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_REPOSITORY ), traceRoot, "$", 1 ).then( () => {
166
- return cache.arrayAppendJSON( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_REPOSITORY ), traceEntry, "$.trace" );
167
- } ).then( () => {
168
- // this will refresh the expiration time for the trace repository on each new record:
169
- let expiration = config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_EXPIRATION_TIME );
170
- return ( expiration > 0 ) ? cache.expireValue( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_REPOSITORY ), expiration ) : expiration;
171
- } ).catch( ( error ) => {
172
- if ( error.code === exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED ) {
173
- cache.addToSet( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_REPOSITORY ), traceEntry ).catch( ( error ) => {
174
- logger.log( `Failed to add message trace entry to the trace repository. While this will not prevent the application from running, it might still be a sign of a more serious problem!`, logger.logSeverity.WARNING, error );
106
+ /* Public interface */
107
+
108
+ /**
109
+ * Used to initialize the message tracer.
110
+ *
111
+ * @method
112
+ * @returns {Promise}
113
+ * @public
114
+ */
115
+ initialize() {
116
+ return new Promise( ( resolve, reject ) => {
117
+ cache.instance.setJSON( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_REPOSITORY ), traceRoot, "$", 1 ).then( () => {
118
+ resolve();
119
+ } ).catch( ( error ) => {
120
+ reject( exceptions.raise( error ) );
175
121
  } );
176
- } else {
177
- logger.log( `Failed to add message trace entry to the trace repository. While this will not prevent the application from running, it might still be a sign of a more serious problem!`, logger.logSeverity.WARNING, error );
122
+ } );
123
+ }
124
+
125
+ /**
126
+ * Used to create a trace entry for the provided {@link Message} and parameters.
127
+ * <br/>
128
+ * NOTE: By default all trace events are stored in the memory cache for further processing and analysis. The
129
+ * location is configured in the MESSAGE_EXCHANGE_TRACE_REPOSITORY setting.
130
+ * <br/>
131
+ * NOTE: Trace events are logged with severity level NOTICE or ERROR for failed dispatches. They still might be
132
+ * filtered out if the minimum log level setting is set too high.
133
+ *
134
+ * @method
135
+ * @param {Message} message The message to trace.
136
+ * @param {TiMessageType} messageType The type of the message.
137
+ * @param {TiDispatchEvent} dispatchEvent The event in the dispatch system that triggered the trace entry.
138
+ * @param {TiMessageState} messageState The state of the message processing.
139
+ * @public
140
+ */
141
+ recordTraceEntry( message, messageType, dispatchEvent, messageState ) {
142
+ // Depending on whether the message comes as request or response, the from and to addresses will be opposite:
143
+ let source = message.source.route + "." + message.source.instanceID;
144
+ let destination = message.destination.route + ( ( message.destination.instanceID != null ) ? "." + message.destination.instanceID : "" );
145
+ let messageSnapshot = MessageTracer.#obscureSensitiveData( message );
146
+ delete messageSnapshot.chainID;
147
+ delete messageSnapshot.messageID;
148
+ let currentDate = new Date();
149
+
150
+ /** @type TiTraceEntry */
151
+ let traceEntry = {
152
+ chainID: message.chainID,
153
+ dispatchEvent: tools.getEnumName( dispatchEventEnum, dispatchEvent ),
154
+ fromAddress: ( messageType === messageTypeEnum.MESSAGE_REQUEST ) ? source : destination,
155
+ messageID: message.messageID,
156
+ messageSnapshot: messageSnapshot,
157
+ messageState: tools.getEnumName( messageStateEnum, messageState ),
158
+ messageType: tools.getEnumName( messageTypeEnum, messageType ),
159
+ toAddress: ( messageType === messageTypeEnum.MESSAGE_REQUEST ) ? destination : source,
160
+ traceTimestamp: currentDate.getTime(),
161
+ traceID: tools.getUUID()
162
+ };
163
+
164
+ // Only write the trace in the general log if this is enabled:
165
+ if ( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_LOG_ENABLED ) === true ) {
166
+ MessageTracer.#createLogEntry( traceEntry, ( dispatchEvent === dispatchEventEnum.FAILED ) ? logger.logSeverity.ERROR : logger.logSeverity.NOTICE );
178
167
  }
179
- } );
180
168
 
181
- };
169
+ // Add the trace entry to the repository in the memory cache:
170
+ cache.instance.arrayAppendJSON( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_REPOSITORY ), traceEntry, "$.trace" ).then( () => {
171
+ // This will refresh the expiration time for the trace repository on each new record:
172
+ let expiration = config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_EXPIRATION_TIME );
173
+ return ( expiration > 0 ) ? cache.instance.expireValue( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_REPOSITORY ), expiration ) : expiration;
174
+ } ).catch( ( error ) => {
175
+ // If JSON is unsupported in Redis server, then try to store the trace entry in a Set:
176
+ if ( error.code === exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED ) {
177
+ cache.instance.addToSet( config.getSetting( config.setting.MESSAGE_EXCHANGE_TRACE_REPOSITORY ), traceEntry ).catch( ( error ) => {
178
+ logger.log( `Failed to add message trace entry to the trace repository. While this will not prevent the application from running, it might still be a sign of a more serious problem!`, logger.logSeverity.WARNING, error );
179
+ } );
180
+ } else {
181
+ logger.log( `Failed to add message trace entry to the trace repository. While this will not prevent the application from running, it might still be a sign of a more serious problem!`, logger.logSeverity.WARNING, error );
182
+ }
183
+ } );
184
+ }
185
+
186
+ /* Private interface */
187
+
188
+ /**
189
+ * Used to create a log entry from the trace entry.
190
+ *
191
+ * @method
192
+ * @param {TiTraceEntry} traceEntry The trace entry to log.
193
+ * @param {TiLogSeverity} severity The log entry severity.
194
+ * @private
195
+ */
196
+ static #createLogEntry( traceEntry, severity ) {
197
+ logger.log( MessageTracer.#formatLogEntry( traceEntry ), severity, traceEntry );
198
+ }
199
+
200
+ /**
201
+ * Used to format trace entry into log-suitable string.
202
+ *
203
+ * @method
204
+ * @param {TiTraceEntry} traceEntry
205
+ * @return {string} Prepared trace info.
206
+ * @private
207
+ */
208
+ static #formatLogEntry( traceEntry ) {
209
+ return `Message(${ traceEntry.chainID || traceEntry.messageID }) Trace: '${ traceEntry.messageType } ${ traceEntry.dispatchEvent } ${ traceEntry.messageState }' From: '${ traceEntry.fromAddress }' To: '${ traceEntry.toAddress }'`;
210
+ }
211
+
212
+ /**
213
+ * Used to obscure sensitive data in the message, remove the payload, and return a snapshot.
214
+ *
215
+ * @method
216
+ * @param {Message} message
217
+ * @returns {Message}
218
+ * @private
219
+ */
220
+ static #obscureSensitiveData( message ) {
221
+ /** @type Message */
222
+ let messageSnapshot = tools.parseJSON( _.replace( tools.stringifyJSON( message ), /("\w*?pin\w*?"|"\w*?pass\w*?"|"\w*?otp\w*?"):"(.*?)"/gmi, "\"SENSITIVE_PROPERTY\":\"OBSCURED_BY_SYSTEM\"" ) );
223
+ delete messageSnapshot.payload;
224
+ return messageSnapshot;
225
+ }
226
+
227
+ }
228
+
229
+ const instance = new MessageTracer();
230
+ module.exports.instance = Object.freeze( instance );