@ti-engine/core 1.0.0
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/components/auditing.js +163 -0
- package/components/connection-observer.js +53 -0
- package/components/exchange/default/default-message-exchange.js +133 -0
- package/components/exchange/default/default-message-receiver.js +89 -0
- package/components/exchange/default/default-message-sender.js +90 -0
- package/components/exchange/message-dispatcher.js +162 -0
- package/components/exchange/message-exchange.js +418 -0
- package/components/exchange/message-handler.js +173 -0
- package/components/exchange/message-memory-cache.js +150 -0
- package/components/exchange/message-observer.js +76 -0
- package/components/exchange/message-receiver.js +113 -0
- package/components/exchange/message-sender.js +133 -0
- package/components/exchange/message-tracer.js +146 -0
- package/components/service-caller.js +306 -0
- package/components/service-consumer.js +112 -0
- package/components/service-executor.js +231 -0
- package/components/service-instance.js +280 -0
- package/components/service-provider.js +221 -0
- package/integrations/gcloud-integration.js +61 -0
- package/integrations/redis-integration.js +261 -0
- package/package.json +54 -0
- package/settings.json +33 -0
- package/utils/cache.js +507 -0
- package/utils/config.js +146 -0
- package/utils/exceptions.js +241 -0
- package/utils/logger.js +69 -0
- package/utils/tools.js +537 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: © 2021 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
3
|
+
* SPDX-License-Identifier: ICU
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const _ = require( "lodash" );
|
|
7
|
+
const tools = require( "#tools" );
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Enum for listing all system-recognized exceptions.
|
|
11
|
+
*
|
|
12
|
+
* @readonly
|
|
13
|
+
* @enum {number}
|
|
14
|
+
*/
|
|
15
|
+
let exceptionCodeEnum = tools.enum( {
|
|
16
|
+
E_UNKNOWN_ERROR: [ 0, "unknown error", "Unidentified error encountered or unrecognized exception code provided." ],
|
|
17
|
+
/** General exceptions - codes under 1xxx */
|
|
18
|
+
E_GEN_JS_INTERNAL_ERROR: [ 1000, "js internal error", "Error thrown by internal JS source." ],
|
|
19
|
+
E_GEN_ABSTRACT_CLASS_INIT: [ 1001, "abstract class init", "Attempt to construct an abstract class detected." ],
|
|
20
|
+
E_GEN_ABSTRACT_METHOD_CALL: [ 1002, "abstract method call", "Attempt to call an abstract method detected." ],
|
|
21
|
+
E_GEN_INVALID_SERVICE_DOMAIN_NAME: [ 1003, "invalid service domain name", "Invalid or no service domain name provided at microservice startup." ],
|
|
22
|
+
E_GEN_SYSTEM_CACHE_UNAVAILABLE: [ 1004, "system cache unavailable", "The system cache required for proper engine operation is unavailable." ],
|
|
23
|
+
E_GEN_BAD_SERVICE_HANDLER: [ 1005, "bad service handler", "The provided service handler is not a proper function." ],
|
|
24
|
+
/** Security & Administration related exceptions - codes under 2xxx */
|
|
25
|
+
E_SEC_INVALID_AUTH_TOKEN: [ 2000, "invalid auth token", "Invalid authorization token provided." ],
|
|
26
|
+
E_SEC_INVALID_EXPIRED_SESSION: [ 2001, "invalid or expired session", "Invalid or expired session encountered." ],
|
|
27
|
+
E_SEC_UNAUTHORIZED_ACCESS: [ 2002, "unauthorized access", "Attempt for unauthorized access detected." ],
|
|
28
|
+
/** Cross-Application Communication exceptions - codes under 3xxx */
|
|
29
|
+
E_COM_GENERAL_ERROR: [ 3000, "general communication error", "General error during cross-application communication." ],
|
|
30
|
+
E_COM_MESSAGE_SENDER_UNAVAILABLE: [ 3001, "message sender unavailable", "The message sender instance is currently unavailable." ],
|
|
31
|
+
E_COM_SERVICE_EXEC_TIMEOUT: [ 3002, "service exec timeout", "The execution of a service could not complete within the allowed timeout." ],
|
|
32
|
+
E_COM_SERVICE_NOT_REGISTERED: [ 3003, "service not registered", "The specified service is not found in the service registry." ],
|
|
33
|
+
E_COM_SERVICE_NOT_FOUND: [ 3004, "service not found", "The specified service is not found in the service definition interface." ],
|
|
34
|
+
E_COM_SERVICE_HANDLER_NOT_FOUND: [ 3005, "service handler not found", "No handler found in the interface for the specified service or service version." ],
|
|
35
|
+
// E_COM_UNRECOGNIZED_API_URL: [ 301, "unrecognized api url", "Attempt to access unrecognized or invalid API URL." ],
|
|
36
|
+
// E_COM_MISSING_REQUIRED_ARGUMENTS: [ 302, "missing required arguments", "Attempt to execute operation without all required arguments." ],
|
|
37
|
+
// E_COM_UNRECOGNIZED_RESPONSE_STRUCTURE: [ 303, "unrecognized response structure", "The received response has unrecognized structure and cannot be parsed or examined." ],
|
|
38
|
+
// E_COM_RECEIVED_ERROR_RESPONSE: [ 304, "received error response", "The received response indicates error in the external system." ],
|
|
39
|
+
// E_COM_JSON_RPC_DATA_INVALID: [ 305, "json rpc data invalid", "The JSON RPC 2.0 data being verified is not valid." ],
|
|
40
|
+
// E_COM_NO_OPEN_CONNECTION: [ 306, "no open connection", "Attempting to do communication request while there is no open connection available." ],
|
|
41
|
+
// E_COM_REQUEST_ERROR_RESPONSE: [ 307, "received error response", "The received response indicates error in the external system." ],
|
|
42
|
+
// E_COM_CONNECTION_TIMEOUT: [ 308, "connection timeout", "Attempting to do communication request but request timeout." ],
|
|
43
|
+
// E_COM_INVALID_API_MAPPING: [ 309, "invalid api mapping", "Attempt to access API URL without proper controller mapping." ],
|
|
44
|
+
E_COM_RETRY_ATTEMPTS_EXCEEDED: [ 3010, "retry attempts exceeded", "Connection retry attempts exceeded the configured limit." ]
|
|
45
|
+
} );
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @typedef {number} TiExceptionCode
|
|
49
|
+
*/
|
|
50
|
+
module.exports.exceptionCode = exceptionCodeEnum;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Represents an exception.
|
|
54
|
+
*
|
|
55
|
+
* @class Exception
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
class Exception {
|
|
59
|
+
|
|
60
|
+
#id = undefined;
|
|
61
|
+
#code = undefined;
|
|
62
|
+
#httpCode = undefined;
|
|
63
|
+
#label = undefined;
|
|
64
|
+
#description = undefined;
|
|
65
|
+
#data = undefined;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @constructor
|
|
69
|
+
* @param {string} id The unique ID to be assigned to this exception.
|
|
70
|
+
* @param {TiExceptionCode} exceptionCode An unique exception identifier. If this is not recognized, the default error code will be used instead.
|
|
71
|
+
* @param {Object} [data] Any additional data to insert into the exception.
|
|
72
|
+
*/
|
|
73
|
+
constructor( id, exceptionCode, data ) {
|
|
74
|
+
exceptionCode = ( exceptionCodeEnum.properties[ exceptionCode ] ) ? exceptionCode : module.exports.exceptionCode.E_UNKNOWN_ERROR;
|
|
75
|
+
|
|
76
|
+
this.#id = id;
|
|
77
|
+
this.#code = exceptionCode;
|
|
78
|
+
this.#httpCode = undefined;
|
|
79
|
+
this.#label = "labels.general.exceptions." + exceptionCode;
|
|
80
|
+
this.#description = exceptionCodeEnum.properties[ exceptionCode ].description;
|
|
81
|
+
this.#data = data || {};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Public interface */
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Unique identifier of the exception instance. Can be used for tracing problems with customer support cases.
|
|
88
|
+
*
|
|
89
|
+
* @method
|
|
90
|
+
* @return {string}
|
|
91
|
+
* @public
|
|
92
|
+
*/
|
|
93
|
+
get id() {
|
|
94
|
+
return this.#id;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Identifier code of the exception type.
|
|
99
|
+
*
|
|
100
|
+
* @method
|
|
101
|
+
* @return {TiExceptionCode}
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
get code() {
|
|
105
|
+
return this.#code;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* HTTP error code if relevant.
|
|
110
|
+
*
|
|
111
|
+
* @method
|
|
112
|
+
* @return {number}
|
|
113
|
+
* @public
|
|
114
|
+
*/
|
|
115
|
+
get httpCode() {
|
|
116
|
+
return this.#httpCode;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* HTTP error code if relevant.
|
|
121
|
+
*
|
|
122
|
+
* @method
|
|
123
|
+
* @param {number} httpCode
|
|
124
|
+
* @public
|
|
125
|
+
*/
|
|
126
|
+
set httpCode( httpCode ) {
|
|
127
|
+
this.#httpCode = httpCode;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Localized label identifier.
|
|
132
|
+
*
|
|
133
|
+
* @method
|
|
134
|
+
* @return {string}
|
|
135
|
+
* @public
|
|
136
|
+
*/
|
|
137
|
+
get label() {
|
|
138
|
+
return this.#label;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Description or additional technical information that is NOT localized.
|
|
143
|
+
*
|
|
144
|
+
* @method
|
|
145
|
+
* @return {string}
|
|
146
|
+
* @public
|
|
147
|
+
*/
|
|
148
|
+
get description() {
|
|
149
|
+
return this.#description;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* JSON containing any additional data that has relevance for the exception. Can be converted JavaScript {@link Error} object as well.
|
|
154
|
+
*
|
|
155
|
+
* @method
|
|
156
|
+
* @return {Object}
|
|
157
|
+
* @public
|
|
158
|
+
*/
|
|
159
|
+
get data() {
|
|
160
|
+
return this.#data;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* JSON containing any additional data that has relevance for the exception. Can be converted JavaScript {@link Error} object as well.
|
|
165
|
+
*
|
|
166
|
+
* @method
|
|
167
|
+
* @param {Object} data
|
|
168
|
+
* @public
|
|
169
|
+
*/
|
|
170
|
+
set data( data ) {
|
|
171
|
+
this.#data = data;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Extracts the essential information about the Exception and returns it as JSON.
|
|
176
|
+
*
|
|
177
|
+
* @method
|
|
178
|
+
* @returns {Object}
|
|
179
|
+
* @public
|
|
180
|
+
*/
|
|
181
|
+
asJSON() {
|
|
182
|
+
return {
|
|
183
|
+
id: this.id,
|
|
184
|
+
code: this.code,
|
|
185
|
+
httpCode: this.httpCode,
|
|
186
|
+
label: this.label,
|
|
187
|
+
description: this.description
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Used to raise an exception from the provided source.
|
|
194
|
+
*
|
|
195
|
+
* @method
|
|
196
|
+
* @param {Error|TiExceptionCode|Exception} source Could be a standard JS Error, an ExceptionCode, or another Exception (in which case it will be raised further).
|
|
197
|
+
* @param {Object} [data] Additional JSON data that can accompany the exception. If more data is added on subsequent Raise calls, it will be merged with the existing one.
|
|
198
|
+
* @param {string} [exceptionID] Should be used only in cases when we have a recognizable exception ID beforehand. Should not be entered otherwise!
|
|
199
|
+
* @returns {Exception}
|
|
200
|
+
* @public
|
|
201
|
+
*/
|
|
202
|
+
module.exports.raise = ( source, data, exceptionID ) => {
|
|
203
|
+
/** @type Exception */
|
|
204
|
+
let exception;
|
|
205
|
+
|
|
206
|
+
if ( source instanceof Error ) {
|
|
207
|
+
exception = new Exception( exceptionID || tools.getUUID(), module.exports.exceptionCode.E_GEN_JS_INTERNAL_ERROR, tools.errorToJSON( source ) );
|
|
208
|
+
} else if ( source instanceof Exception ) {
|
|
209
|
+
exception = source;
|
|
210
|
+
} else if ( _.isString( source ) ) {
|
|
211
|
+
exception = new Exception( exceptionID || tools.getUUID(), module.exports.exceptionCode.E_GEN_JS_INTERNAL_ERROR, {
|
|
212
|
+
message: source
|
|
213
|
+
} );
|
|
214
|
+
} else {
|
|
215
|
+
exception = new Exception( exceptionID || tools.getUUID(), ( exceptionCodeEnum.properties[ source ] ) ? source : module.exports.exceptionCode.E_UNKNOWN_ERROR );
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// merge the default exception data with the additional one, if it's provided:
|
|
219
|
+
if ( data ) {
|
|
220
|
+
exception.data = _.mergeWith( ( exception.data || {} ), _.cloneDeep( data ), ( objValue, srcValue ) => {
|
|
221
|
+
return ( _.isArray( objValue ) ) ? objValue.concat( srcValue ) : undefined;
|
|
222
|
+
} );
|
|
223
|
+
|
|
224
|
+
// make sure to eliminate any circular dependencies inside the data object (these should never be needed for an error description):
|
|
225
|
+
exception.data = tools.decycle( exception.data );
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return exception;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Verifies if the passed object is an Exception.
|
|
233
|
+
*
|
|
234
|
+
* @method
|
|
235
|
+
* @param object
|
|
236
|
+
* @returns {boolean}
|
|
237
|
+
* @public
|
|
238
|
+
*/
|
|
239
|
+
module.exports.isException = ( object ) => {
|
|
240
|
+
return ( object instanceof Exception );
|
|
241
|
+
};
|
package/utils/logger.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: © 2021 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
3
|
+
* SPDX-License-Identifier: ICU
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const _ = require( "lodash" );
|
|
7
|
+
const tools = require( "#tools" );
|
|
8
|
+
const exceptions = require( "#exceptions" );
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Enum for specifying the log entry severity. This is based on the Google Stackdriver severity levels.
|
|
12
|
+
*
|
|
13
|
+
* @readonly
|
|
14
|
+
* @enum {number}
|
|
15
|
+
*/
|
|
16
|
+
let logSeverityEnum = tools.enum( {
|
|
17
|
+
DEFAULT: [ 0, "default", "The log entry has no assigned severity level." ],
|
|
18
|
+
DEBUG: [ 100, "debug", "Debug or trace information." ],
|
|
19
|
+
INFO: [ 200, "info", "Routine information, such as ongoing status or performance." ],
|
|
20
|
+
NOTICE: [ 300, "notice", "Normal but significant events, such as start up, shut down, or a configuration change." ],
|
|
21
|
+
WARNING: [ 400, "warning", "Warning events might cause problems." ],
|
|
22
|
+
ERROR: [ 500, "error", "Error events are likely to cause problems." ],
|
|
23
|
+
CRITICAL: [ 600, "critical", "Critical events cause more severe problems or outages." ],
|
|
24
|
+
ALERT: [ 700, "alert", "A person must take an action immediately." ],
|
|
25
|
+
EMERGENCY: [ 800, "emergency", "One or more systems are unusable." ]
|
|
26
|
+
} );
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @typedef {number} TiLogSeverity
|
|
30
|
+
*/
|
|
31
|
+
module.exports.logSeverity = logSeverityEnum;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Used to safely return the name of a severity code.
|
|
35
|
+
*
|
|
36
|
+
* @method
|
|
37
|
+
* @param {TiLogSeverity} severity
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
module.exports.getSeverityName = ( severity ) => {
|
|
41
|
+
return tools.getEnumName( logSeverityEnum, severity, "unknown" );
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Used to generate and store a log entry in the active cache.
|
|
46
|
+
*
|
|
47
|
+
* @method
|
|
48
|
+
* @param {string} message The primary log message.
|
|
49
|
+
* @param {TiLogSeverity} [level=DEFAULT] The log severity level. If the current log filtering setting is higher than this then the log entry will be ignored.
|
|
50
|
+
* @param {Object|Error|Exception} [data={}] Optional JSON data containing details of the log entry.
|
|
51
|
+
* @param {string} [thread='main'] The logging thread to which the log entry belongs.
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
module.exports.log = ( message, level = logSeverityEnum.DEFAULT, data = {}, thread = "main" ) => {
|
|
55
|
+
/** @type {Auditing} */
|
|
56
|
+
const auditing = require( "#auditing" );
|
|
57
|
+
|
|
58
|
+
if ( data instanceof Error ) {
|
|
59
|
+
data = tools.errorToJSON( data );
|
|
60
|
+
} else if ( exceptions.isException( data ) ) {
|
|
61
|
+
data = {
|
|
62
|
+
id: data.id,
|
|
63
|
+
description: data.description,
|
|
64
|
+
details: !_.isEmpty( data.data ) ? data.data : undefined
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
auditing.log( message, level, thread, data );
|
|
69
|
+
};
|