@ti-engine/core 1.3.13 → 1.6.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/CHANGELOG.md +70 -1
- package/README.md +3 -3
- package/bin/localization/labels.json +9 -0
- package/bin/settings.json +1 -1
- package/components/auditing.js +1 -18
- package/components/connection-observer.js +2 -2
- package/components/definitions.types.js +248 -0
- package/components/exchange/message-dispatcher.js +1 -1
- package/components/exchange/message-exchange.js +6 -30
- package/components/exchange/message-handler.js +16 -6
- package/components/exchange/message-memory-cache.js +1 -1
- package/components/exchange/message-observer.js +2 -2
- package/components/exchange/message-receiver.js +4 -3
- package/components/exchange/message-sender.js +2 -2
- package/components/exchange/message-tracer.js +4 -27
- package/components/service-caller.js +1 -40
- package/components/service-consumer.js +1 -1
- package/components/service-executor.js +1 -16
- package/components/service-instance.js +4 -9
- package/components/service-provider.js +9 -8
- package/integrations/redis-integration.js +8 -13
- package/package.json +10 -11
- package/utils/cache.js +64 -18
- package/utils/config.js +4 -101
- package/utils/exceptions.js +37 -20
- package/utils/localization.js +2 -17
- package/utils/logger.js +5 -8
- package/utils/tools.js +25 -20
- package/integrations/gcloud-integration.js +0 -65
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
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-
|
|
3
|
+
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
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
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
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/>.
|
|
@@ -23,7 +23,7 @@ class MessageSender extends MessageHandler {
|
|
|
23
23
|
/**
|
|
24
24
|
* @constructor
|
|
25
25
|
* @param {string} identifier An identifier for this message handler. Should be unique in the context of the message exchange.
|
|
26
|
-
* @throws {
|
|
26
|
+
* @throws {TiException.E_GEN_ABSTRACT_CLASS_INIT} If this class is instantiated directly.
|
|
27
27
|
*/
|
|
28
28
|
constructor( identifier ) {
|
|
29
29
|
super( identifier );
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
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-
|
|
3
|
+
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
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
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
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/>.
|
|
@@ -13,20 +13,6 @@ const logger = require( "#logger" );
|
|
|
13
13
|
const exceptions = require( "#exceptions" );
|
|
14
14
|
const cache = require( "#cache" );
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* @typedef {Object} TiTraceEntry
|
|
18
|
-
* @property {string} chainID
|
|
19
|
-
* @property {string} dispatchEvent
|
|
20
|
-
* @property {string} fromAddress
|
|
21
|
-
* @property {string} messageID
|
|
22
|
-
* @property {Object} messageSnapshot
|
|
23
|
-
* @property {string} messageState
|
|
24
|
-
* @property {string} messageType
|
|
25
|
-
* @property {string} toAddress
|
|
26
|
-
* @property {string} traceID
|
|
27
|
-
* @property {number} traceTimestamp
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
16
|
const traceRoot = {
|
|
31
17
|
trace: []
|
|
32
18
|
};
|
|
@@ -37,15 +23,12 @@ const UNKNOWN_TOKEN = "UNKNOWN";
|
|
|
37
23
|
*
|
|
38
24
|
* @readonly
|
|
39
25
|
* @enum {number}
|
|
26
|
+
* @typedef {number} TiMessageType
|
|
40
27
|
*/
|
|
41
28
|
let messageTypeEnum = tools.enum( {
|
|
42
29
|
MESSAGE_REQUEST: [ 1000, "REQUEST", "" ],
|
|
43
30
|
MESSAGE_RESPONSE: [ 1001, "RESPONSE", "" ]
|
|
44
31
|
} );
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* @typedef {number} TiMessageType
|
|
48
|
-
*/
|
|
49
32
|
module.exports.messageType = messageTypeEnum;
|
|
50
33
|
|
|
51
34
|
/**
|
|
@@ -53,6 +36,7 @@ module.exports.messageType = messageTypeEnum;
|
|
|
53
36
|
*
|
|
54
37
|
* @readonly
|
|
55
38
|
* @enum {number}
|
|
39
|
+
* @typedef {number} TiDispatchEvent
|
|
56
40
|
*/
|
|
57
41
|
let dispatchEventEnum = tools.enum( {
|
|
58
42
|
DELIVERED: [ 1100, "DELIVERED", "When message delivery is confirmed." ],
|
|
@@ -60,10 +44,6 @@ let dispatchEventEnum = tools.enum( {
|
|
|
60
44
|
RECEIVED: [ 1102, "RECEIVED", "When message was received." ],
|
|
61
45
|
SENT: [ 1103, "SENT", "When message was sent." ]
|
|
62
46
|
} );
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @typedef {number} TiDispatchEvent
|
|
66
|
-
*/
|
|
67
47
|
module.exports.dispatchEvent = dispatchEventEnum;
|
|
68
48
|
|
|
69
49
|
/**
|
|
@@ -71,15 +51,12 @@ module.exports.dispatchEvent = dispatchEventEnum;
|
|
|
71
51
|
*
|
|
72
52
|
* @readonly
|
|
73
53
|
* @enum {number}
|
|
54
|
+
* @typedef {number} TiMessageState
|
|
74
55
|
*/
|
|
75
56
|
let messageStateEnum = tools.enum( {
|
|
76
57
|
PENDING: [ 1200, "PENDING", "" ],
|
|
77
58
|
PROCESSED: [ 1201, "PROCESSED", "" ]
|
|
78
59
|
} );
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @typedef {number} TiMessageState
|
|
82
|
-
*/
|
|
83
60
|
module.exports.messageState = messageStateEnum;
|
|
84
61
|
|
|
85
62
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
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-
|
|
3
|
+
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
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
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
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/>.
|
|
@@ -14,45 +14,6 @@ const config = require( "#config" );
|
|
|
14
14
|
const cache = require( "#cache" );
|
|
15
15
|
const messageDispatcher = require( "#message-dispatcher" );
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {Object} ServiceAddress
|
|
19
|
-
* @property {string} serviceAlias A valid service alias.
|
|
20
|
-
* @property {string} serviceDomainName A valid service domain name.
|
|
21
|
-
* @property {number|undefined} serviceVersion Optional service version. If not provided, the latest version will be assumed as a target.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @typedef {Object} ServiceExecContext
|
|
26
|
-
* @property {string|undefined} authToken A valid authentication token that initialized the service call (if applicable).
|
|
27
|
-
* @property {ServiceCallPredecessor|undefined} previousServiceCall The previous service call in the execution chain (if such exists).
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @typedef {Message} ServiceCallPredecessor
|
|
32
|
-
* @property {string} predecessor The {@link Message.messageID} of the predecessor in the service call tree.
|
|
33
|
-
* @property {ServiceAddress} serviceAddress The address of the service that has to process the service call.
|
|
34
|
-
* @property {Object|undefined} serviceParams The named params to be provided to the API service.
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @typedef {ServiceCallPredecessor} ServiceCall
|
|
39
|
-
* @property {string} authToken A valid authentication token that initialized the service call.
|
|
40
|
-
* @property {number} createdOn A unix timestamp taken at creation time of the service call.
|
|
41
|
-
* @property {number} executionTime The total execution time of this service call in milliseconds.
|
|
42
|
-
* @property {Object|undefined} exception If there was exception during the service call processing, it will be set here. Otherwise, it will be 'undefined'.
|
|
43
|
-
* @property {number|undefined} finishedOn A unix timestamp taken at finish time of the service call.
|
|
44
|
-
* @property {boolean} isCompleted Flag to indicate if this service call has been completed.
|
|
45
|
-
* @property {boolean|undefined} isSuccessful A flag indicating if this service call can be considered successful or not. Will be 'undefined' until the service call is processed.
|
|
46
|
-
* @property {string[]} successors The service call IDs of the successors in the service call tree.
|
|
47
|
-
*/
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* @typedef {Object} ServiceCallResult
|
|
51
|
-
* @property {Exception|undefined} exception If there was exception during the service call processing, it will be set here. Otherwise, it will be 'undefined'.
|
|
52
|
-
* @property {boolean} isSuccessful A flag indicating if this service call can be considered successful or not.
|
|
53
|
-
* @property {Object|string|undefined} payload The payload containing the results from the service call processing. If a string, it is ID of the payload in the memory cache instead.
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
17
|
/**
|
|
57
18
|
* Used to assemble and prepare a new {@link ServiceCall} object.
|
|
58
19
|
*
|
|
@@ -33,7 +33,7 @@ class ServiceConsumer extends ServiceInstance {
|
|
|
33
33
|
* @constructor
|
|
34
34
|
* @param {string} serviceDomainName The service domain name for this service instance.
|
|
35
35
|
* @param {ServiceConfiguration} [serviceConfig] The JSON configuration for this service.
|
|
36
|
-
* @throws {
|
|
36
|
+
* @throws {TiException.E_GEN_ABSTRACT_CLASS_INIT} If this class is instantiated directly.
|
|
37
37
|
*/
|
|
38
38
|
constructor( serviceDomainName, serviceConfig ) {
|
|
39
39
|
super( serviceDomainName, serviceConfig );
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
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-
|
|
3
|
+
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
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
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
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/>.
|
|
@@ -15,21 +15,6 @@ const config = require( "#config" );
|
|
|
15
15
|
const cache = require( "#cache" );
|
|
16
16
|
const messageDispatcher = require( "#message-dispatcher" );
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* @typedef {Object} ServiceDefinition
|
|
20
|
-
* @property {string} serviceAlias Service alias.
|
|
21
|
-
* @property {string} serviceFile The JS file containing the service itself. This has to be exposed via package.json import structure!
|
|
22
|
-
* @property {number} [serviceVersion] Service version.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @typedef {Object.<string, ServiceInterfaceVersion>} ServiceInterface
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @typedef {Object.<number, ServiceHandlerMethod>} ServiceInterfaceVersion
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
18
|
/**
|
|
34
19
|
* @callback VerifyAccessMethod
|
|
35
20
|
* @param {string} authToken
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
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-
|
|
3
|
+
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
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
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
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/>.
|
|
@@ -15,11 +15,6 @@ const exceptions = require( "#exceptions" );
|
|
|
15
15
|
const cache = require( "#cache" );
|
|
16
16
|
const messageDispatcher = require( "#message-dispatcher" );
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* @typedef {Object} ServiceConfiguration
|
|
20
|
-
* @property {ServiceDefinition[]} [services] A list of service definitions to be registered with the {@link ServiceProvider}.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
18
|
/**
|
|
24
19
|
* Abstract class used to define a Service Instance behavior.
|
|
25
20
|
* <br/>
|
|
@@ -43,8 +38,8 @@ class ServiceInstance {
|
|
|
43
38
|
* @constructor
|
|
44
39
|
* @param {string} serviceDomainName The service domain name for this service instance.
|
|
45
40
|
* @param {ServiceConfiguration} [serviceConfig={ services: [] }] The JSON configuration for this service.
|
|
46
|
-
* @throws {
|
|
47
|
-
* @throws {
|
|
41
|
+
* @throws {TiException.E_GEN_ABSTRACT_CLASS_INIT} If this class is instantiated directly.
|
|
42
|
+
* @throws {TiException.E_GEN_FEATURE_UNSUPPORTED} If multiple instances are started in the same process.
|
|
48
43
|
*/
|
|
49
44
|
constructor( serviceDomainName, serviceConfig = { services: [] } ) {
|
|
50
45
|
// Ensure this abstract class cannot be instantiated:
|
|
@@ -143,7 +138,7 @@ class ServiceInstance {
|
|
|
143
138
|
* <br/>
|
|
144
139
|
* NOTE: This method will be invoked automatically.
|
|
145
140
|
* <br/>
|
|
146
|
-
* NOTE: If you need to add more onStart logic you can override this method but make sure to call it in the
|
|
141
|
+
* NOTE: If you need to add more onStart logic, you can override this method but make sure to call it in the
|
|
147
142
|
* overriding method using: super.onStart()
|
|
148
143
|
*
|
|
149
144
|
* @method
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
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-
|
|
3
|
+
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
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
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
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/>.
|
|
@@ -38,7 +38,7 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
38
38
|
* @constructor
|
|
39
39
|
* @param {string} serviceDomainName The service domain name for this service instance.
|
|
40
40
|
* @param {ServiceConfiguration} [serviceConfig] The JSON configuration for this service.
|
|
41
|
-
* @throws {
|
|
41
|
+
* @throws {TiException.E_GEN_ABSTRACT_CLASS_INIT} If this class is instantiated directly.
|
|
42
42
|
*/
|
|
43
43
|
constructor( serviceDomainName, serviceConfig ) {
|
|
44
44
|
super( serviceDomainName, serviceConfig );
|
|
@@ -56,7 +56,7 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
56
56
|
* <br/>
|
|
57
57
|
* NOTE: This method will be invoked automatically.
|
|
58
58
|
* <br/>
|
|
59
|
-
* NOTE: If you need to add more onStart logic you can override this method but make sure to call it in the
|
|
59
|
+
* NOTE: If you need to add more onStart logic, you can override this method but make sure to call it in the
|
|
60
60
|
* overriding method using: super.onStart()
|
|
61
61
|
*
|
|
62
62
|
* @method
|
|
@@ -88,7 +88,7 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
88
88
|
* <br/>
|
|
89
89
|
* NOTE: This method will be invoked automatically.
|
|
90
90
|
* <br/>
|
|
91
|
-
* NOTE: If you need to add more onStop logic you can override this method but make sure to call it in the
|
|
91
|
+
* NOTE: If you need to add more onStop logic, you can override this method but make sure to call it in the
|
|
92
92
|
* overriding method using: super.onStop()
|
|
93
93
|
*
|
|
94
94
|
* @method
|
|
@@ -110,7 +110,7 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
110
110
|
* Used to report health status of the service instance for external monitoring.
|
|
111
111
|
* This is a scheduled job that will be executed at SERVICE_HEALTH_CHECK_INTERVAL time.
|
|
112
112
|
* <br/>
|
|
113
|
-
* NOTE: By default this method will update a Redis key with an expiration timer. You can override this
|
|
113
|
+
* NOTE: By default, this method will update a Redis key with an expiration timer. You can override this
|
|
114
114
|
* functionality with something custom like calling an HTTP endpoint.
|
|
115
115
|
*
|
|
116
116
|
* @method
|
|
@@ -204,13 +204,14 @@ class ServiceProvider extends ServiceConsumer {
|
|
|
204
204
|
let promises = [];
|
|
205
205
|
_.forEach( serviceDefinitions, ( serviceDefinition ) => {
|
|
206
206
|
// NOTE: we are not going to interrupt the service interface loading if one of the services fails to load or is not found!
|
|
207
|
-
// If this happens, a corresponding log entry will be created but the loading process will continue. Therefore, the following
|
|
208
|
-
// promise will always
|
|
207
|
+
// If this happens, a corresponding log entry will be created, but the loading process will continue. Therefore, the following
|
|
208
|
+
// promise will always be resolved (unless a programming error occurs in it, of course).
|
|
209
209
|
let registrationPromise = ( serviceDefinition, defaultServiceHandler ) => {
|
|
210
210
|
return new Promise( ( resolve ) => {
|
|
211
211
|
this.registerService( serviceDefinition, defaultServiceHandler ).then( () => {
|
|
212
212
|
resolve( true );
|
|
213
|
-
} ).catch( () => {
|
|
213
|
+
} ).catch( ( error ) => {
|
|
214
|
+
logger.log( `Service registration failed for '${ serviceDefinition?.serviceAlias || "unknown-service" }'.`, logger.logSeverity.ERROR, error );
|
|
214
215
|
resolve( false );
|
|
215
216
|
} );
|
|
216
217
|
} );
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
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-
|
|
3
|
+
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
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
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
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/>.
|
|
@@ -18,6 +18,7 @@ const _ = require( "lodash" );
|
|
|
18
18
|
*
|
|
19
19
|
* @readonly
|
|
20
20
|
* @enum {string}
|
|
21
|
+
* @typedef {string} TiRedisCommand
|
|
21
22
|
*/
|
|
22
23
|
let cacheCommandsEnum = tools.enum( {
|
|
23
24
|
ADD_TO_SET: [ "sadd", "add to set", "https://redis.io/docs/latest/commands/sadd/" ],
|
|
@@ -34,6 +35,8 @@ let cacheCommandsEnum = tools.enum( {
|
|
|
34
35
|
IS_SET_MEMBER: [ "sismember", "", "https://redis.io/docs/latest/commands/sismember/" ],
|
|
35
36
|
JSON_ARRAY_APPEND: [ "json.arrappend", "", "https://redis.io/docs/latest/commands/json.arrappend/" ],
|
|
36
37
|
JSON_GET: [ "json.get", "", "https://redis.io/docs/latest/commands/json.get/" ],
|
|
38
|
+
JSON_MERGE: [ "json.merge", "", "https://redis.io/docs/latest/commands/json.merge/" ],
|
|
39
|
+
JSON_MGET: [ "json.mget", "", "https://redis.io/docs/latest/commands/json.mget/" ],
|
|
37
40
|
JSON_SET: [ "json.set", "", "https://redis.io/docs/latest/commands/json.set/" ],
|
|
38
41
|
KEYS: [ "keys", "(warning: O(N), use SCAN where possible)", "https://redis.io/docs/latest/commands/keys/" ],
|
|
39
42
|
LIST_PUSH: [ "lpush", "list push", "https://redis.io/docs/latest/commands/lpush/" ],
|
|
@@ -43,12 +46,14 @@ let cacheCommandsEnum = tools.enum( {
|
|
|
43
46
|
SET_VALUE: [ "set", "set value", "https://redis.io/docs/latest/commands/set/" ],
|
|
44
47
|
UNION_OF_SETS: [ "sunion", "union of sets", "https://redis.io/docs/latest/commands/sunion/" ]
|
|
45
48
|
} );
|
|
49
|
+
module.exports.cacheCommands = cacheCommandsEnum;
|
|
46
50
|
|
|
47
51
|
/**
|
|
48
52
|
* Enum for listing all client statuses.
|
|
49
53
|
*
|
|
50
54
|
* @readonly
|
|
51
55
|
* @enum {number}
|
|
56
|
+
* @typedef {number} TiRedisClientStatus
|
|
52
57
|
*/
|
|
53
58
|
let clientStatusEnum = tools.enum( {
|
|
54
59
|
UNINITIALIZED: [ 0, "uninitialized", "Redis client is offline and not yet initialized." ],
|
|
@@ -58,31 +63,21 @@ let clientStatusEnum = tools.enum( {
|
|
|
58
63
|
SHUTTING_DOWN: [ 4, "shutting down", "Redis client is shutting down." ],
|
|
59
64
|
DISCONNECTED: [ 5, "disconnected", "Redis client is permanently disconnected from server." ]
|
|
60
65
|
} );
|
|
66
|
+
module.exports.clientStatus = clientStatusEnum;
|
|
61
67
|
|
|
62
68
|
/**
|
|
63
69
|
* Enum for listing the Redis key override modes.
|
|
64
70
|
*
|
|
65
71
|
* @readonly
|
|
66
72
|
* @enum {string}
|
|
73
|
+
* @typedef {string} TiRedisOverrideMode
|
|
67
74
|
*/
|
|
68
75
|
let cacheOverrideModeEnum = tools.enum( {
|
|
69
76
|
DEFAULT: [ "", "default", "Standard Redis behaviour when setting new key." ],
|
|
70
77
|
NX: [ "nx", "nx", "Sets the key only if it does not already exist." ],
|
|
71
78
|
XX: [ "xx", "xx", "Sets the key only if it already exists." ]
|
|
72
79
|
} );
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* @typedef {string} TiRedisCommand
|
|
76
|
-
*/
|
|
77
|
-
module.exports.cacheCommands = cacheCommandsEnum;
|
|
78
|
-
/**
|
|
79
|
-
* @typedef {string} TiRedisOverrideMode
|
|
80
|
-
*/
|
|
81
80
|
module.exports.cacheOverrideMode = cacheOverrideModeEnum;
|
|
82
|
-
/**
|
|
83
|
-
* @typedef {number} TiRedisClientStatus
|
|
84
|
-
*/
|
|
85
|
-
module.exports.clientStatus = clientStatusEnum;
|
|
86
81
|
|
|
87
82
|
/**
|
|
88
83
|
* Used to create a Redis Cache client.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ti-engine/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "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.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"microservices",
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
"./service-provider": "./components/service-provider.js",
|
|
27
27
|
"./tools": "./utils/tools.js"
|
|
28
28
|
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"test": "node --test"
|
|
31
|
+
},
|
|
29
32
|
"imports": {
|
|
30
33
|
"#auditing": "./components/auditing.js",
|
|
31
34
|
"#cache": "./utils/cache.js",
|
|
@@ -35,7 +38,6 @@
|
|
|
35
38
|
"#default-message-receiver": "./components/exchange/default/default-message-receiver.js",
|
|
36
39
|
"#default-message-sender": "./components/exchange/default/default-message-sender.js",
|
|
37
40
|
"#exceptions": "./utils/exceptions.js",
|
|
38
|
-
"#gcloud-integration": "./integrations/gcloud-integration.js",
|
|
39
41
|
"#labels": "./bin/localization/labels.json",
|
|
40
42
|
"#localization": "./utils/localization.js",
|
|
41
43
|
"#logger": "./utils/logger.js",
|
|
@@ -57,15 +59,12 @@
|
|
|
57
59
|
"#tools": "./utils/tools.js"
|
|
58
60
|
},
|
|
59
61
|
"dependencies": {
|
|
60
|
-
"@dotenvx/dotenvx": "^1.
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"lodash": "^4.17.21",
|
|
62
|
+
"@dotenvx/dotenvx": "^1.73.1",
|
|
63
|
+
"ioredis": "^5.11.1",
|
|
64
|
+
"lodash": "^4.18.1",
|
|
64
65
|
"node-schedule": "^2.1.1"
|
|
65
66
|
},
|
|
66
67
|
"optionalDependencies": {
|
|
67
|
-
"@google-cloud/error-reporting": "^3.0.5",
|
|
68
|
-
"zeromq": "^6.5.0"
|
|
69
68
|
},
|
|
70
69
|
"files": [
|
|
71
70
|
"bin/",
|
|
@@ -75,7 +74,7 @@
|
|
|
75
74
|
"package.json",
|
|
76
75
|
"README.md",
|
|
77
76
|
"CHANGELOG.md",
|
|
78
|
-
"LICENSE"
|
|
77
|
+
"LICENSE.md"
|
|
79
78
|
],
|
|
80
79
|
"repository": {
|
|
81
80
|
"type": "git",
|
|
@@ -87,6 +86,6 @@
|
|
|
87
86
|
},
|
|
88
87
|
"homepage": "https://github.com/Belleal/ti-engine/tree/master/packages/core#readme",
|
|
89
88
|
"engines": {
|
|
90
|
-
"node": ">=
|
|
89
|
+
"node": ">=20.0.0"
|
|
91
90
|
}
|
|
92
|
-
}
|
|
91
|
+
}
|
package/utils/cache.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
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-
|
|
3
|
+
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
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
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
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/>.
|
|
@@ -129,7 +129,7 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
129
129
|
*
|
|
130
130
|
* @method
|
|
131
131
|
* @param {string} identifier The identifier of the observed connection.
|
|
132
|
-
* @throws {
|
|
132
|
+
* @throws {TiException.E_GEN_SYSTEM_CACHE_UNAVAILABLE} If the cache service is no longer available.
|
|
133
133
|
* @override
|
|
134
134
|
* @public
|
|
135
135
|
*/
|
|
@@ -341,12 +341,7 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
341
341
|
expireValue( key, seconds, name ) {
|
|
342
342
|
return new Promise( ( resolve, reject ) => {
|
|
343
343
|
if ( this.#isOperational === true ) {
|
|
344
|
-
let commandExpire = [];
|
|
345
|
-
if ( name ) {
|
|
346
|
-
commandExpire = [ redis.cacheCommands.HASH_EXPIRE, name, seconds, "FIELDS", 1, key ];
|
|
347
|
-
} else {
|
|
348
|
-
commandExpire = [ redis.cacheCommands.EXPIRE, key, seconds ];
|
|
349
|
-
}
|
|
344
|
+
let commandExpire = ( name ) ? [ redis.cacheCommands.HASH_EXPIRE, name, seconds, "FIELDS", 1, key ] : [ redis.cacheCommands.EXPIRE, key, seconds ];
|
|
350
345
|
this.#redisClient.executeCommands( [ commandExpire ] ).then( () => {
|
|
351
346
|
resolve( seconds );
|
|
352
347
|
} ).catch( ( error ) => {
|
|
@@ -632,7 +627,7 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
632
627
|
* @method
|
|
633
628
|
* @param {string} key
|
|
634
629
|
* @param {Object} value
|
|
635
|
-
* @param {string} [path=
|
|
630
|
+
* @param {string|string[]} [path="$"] A dot-separated JSONPath string, or an array of literal key segments (use the array form when key names may contain dots or other special characters).
|
|
636
631
|
* @param {number} [overrideMode=0] By default this allows full override for existing keys.
|
|
637
632
|
* Option 1 will set the key only if it doesn't already exist. Option 2 will set it only if it already exists.
|
|
638
633
|
* @returns {Promise}
|
|
@@ -642,7 +637,7 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
642
637
|
return new Promise( ( resolve, reject ) => {
|
|
643
638
|
if ( this.#isOperational === true ) {
|
|
644
639
|
if ( this.#redisClient.isJSONSupported ) {
|
|
645
|
-
let commandArguments = [ redis.cacheCommands.JSON_SET, key, path, tools.stringifyJSON( value ) ];
|
|
640
|
+
let commandArguments = [ redis.cacheCommands.JSON_SET, key, this.#normalizeJSONPath( path ), tools.stringifyJSON( value ) ];
|
|
646
641
|
if ( overrideMode !== 0 ) {
|
|
647
642
|
commandArguments.push( overrideMode === 1 ? redis.cacheOverrideMode.NX : redis.cacheOverrideMode.XX );
|
|
648
643
|
}
|
|
@@ -652,7 +647,7 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
652
647
|
reject( error );
|
|
653
648
|
} );
|
|
654
649
|
} else {
|
|
655
|
-
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED
|
|
650
|
+
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED, { details: "No RedisJSON module installed on server." } ) );
|
|
656
651
|
}
|
|
657
652
|
} else {
|
|
658
653
|
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_SYSTEM_CACHE_UNAVAILABLE ) );
|
|
@@ -667,7 +662,7 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
667
662
|
*
|
|
668
663
|
* @method
|
|
669
664
|
* @param {string} key
|
|
670
|
-
* @param {string} path
|
|
665
|
+
* @param {string|string[]} [path="$"] A dot-separated JSONPath string, or an array of literal key segments (use the array form when key names may contain dots or other special characters).
|
|
671
666
|
* @returns {Promise<Object>}
|
|
672
667
|
* @public
|
|
673
668
|
*/
|
|
@@ -675,14 +670,45 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
675
670
|
return new Promise( ( resolve, reject ) => {
|
|
676
671
|
if ( this.#isOperational === true ) {
|
|
677
672
|
if ( this.#redisClient.isJSONSupported ) {
|
|
678
|
-
let commandArguments = [ redis.cacheCommands.JSON_GET, key, path ];
|
|
673
|
+
let commandArguments = [ redis.cacheCommands.JSON_GET, key, this.#normalizeJSONPath( path ) ];
|
|
679
674
|
this.#redisClient.callCommand( commandArguments ).then( ( result ) => {
|
|
680
|
-
resolve( tools.parseJSON( result ) );
|
|
675
|
+
resolve( result != null ? tools.parseJSON( String( result ) ) : null );
|
|
676
|
+
} ).catch( ( error ) => {
|
|
677
|
+
reject( error );
|
|
678
|
+
} );
|
|
679
|
+
} else {
|
|
680
|
+
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED, { details: "No RedisJSON module installed on server." } ) );
|
|
681
|
+
}
|
|
682
|
+
} else {
|
|
683
|
+
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_SYSTEM_CACHE_UNAVAILABLE ) );
|
|
684
|
+
}
|
|
685
|
+
} );
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Used to update/edit an existing JSON variable.
|
|
690
|
+
* <br/>
|
|
691
|
+
* NOTE: Requires ReJSON module installed on server to work.
|
|
692
|
+
*
|
|
693
|
+
* @method
|
|
694
|
+
* @param {string} key
|
|
695
|
+
* @param {Object} value
|
|
696
|
+
* @param {string|string[]} [path="$"] A dot-separated JSONPath string, or an array of literal key segments (use the array form when key names may contain dots or other special characters).
|
|
697
|
+
* @returns {Promise}
|
|
698
|
+
* @public
|
|
699
|
+
*/
|
|
700
|
+
editJSON( key, value, path = "$" ) {
|
|
701
|
+
return new Promise( ( resolve, reject ) => {
|
|
702
|
+
if ( this.#isOperational === true ) {
|
|
703
|
+
if ( this.#redisClient.isJSONSupported ) {
|
|
704
|
+
let commandArguments = [ redis.cacheCommands.JSON_MERGE, key, this.#normalizeJSONPath( path ), tools.stringifyJSON( value ) ];
|
|
705
|
+
this.#redisClient.callCommand( commandArguments ).then( () => {
|
|
706
|
+
resolve();
|
|
681
707
|
} ).catch( ( error ) => {
|
|
682
708
|
reject( error );
|
|
683
709
|
} );
|
|
684
710
|
} else {
|
|
685
|
-
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED
|
|
711
|
+
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED, { details: "No RedisJSON module installed on server." } ) );
|
|
686
712
|
}
|
|
687
713
|
} else {
|
|
688
714
|
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_SYSTEM_CACHE_UNAVAILABLE ) );
|
|
@@ -698,7 +724,7 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
698
724
|
* @method
|
|
699
725
|
* @param {string} key
|
|
700
726
|
* @param {Object} value
|
|
701
|
-
* @param {string} path
|
|
727
|
+
* @param {string|string[]} [path="$"] A dot-separated JSONPath string, or an array of literal key segments (use the array form when key names may contain dots or other special characters).
|
|
702
728
|
* @returns {Promise}
|
|
703
729
|
* @public
|
|
704
730
|
*/
|
|
@@ -706,14 +732,14 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
706
732
|
return new Promise( ( resolve, reject ) => {
|
|
707
733
|
if ( this.#isOperational === true ) {
|
|
708
734
|
if ( this.#redisClient.isJSONSupported ) {
|
|
709
|
-
let commandArguments = [ redis.cacheCommands.JSON_ARRAY_APPEND, key, path, tools.stringifyJSON( value ) ];
|
|
735
|
+
let commandArguments = [ redis.cacheCommands.JSON_ARRAY_APPEND, key, this.#normalizeJSONPath( path ), tools.stringifyJSON( value ) ];
|
|
710
736
|
this.#redisClient.callCommand( commandArguments ).then( () => {
|
|
711
737
|
resolve();
|
|
712
738
|
} ).catch( ( error ) => {
|
|
713
739
|
reject( error );
|
|
714
740
|
} );
|
|
715
741
|
} else {
|
|
716
|
-
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED
|
|
742
|
+
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_FEATURE_UNSUPPORTED, { details: "No RedisJSON module installed on server." } ) );
|
|
717
743
|
}
|
|
718
744
|
} else {
|
|
719
745
|
reject( exceptions.raise( exceptions.exceptionCode.E_GEN_SYSTEM_CACHE_UNAVAILABLE ) );
|
|
@@ -721,6 +747,26 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
721
747
|
} );
|
|
722
748
|
}
|
|
723
749
|
|
|
750
|
+
/* Private interface */
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Used to normalize a JSON path.
|
|
754
|
+
* <br/>
|
|
755
|
+
* NOTE: If "path" is an array, each element is treated as a literal key name and encoded with bracket notation,
|
|
756
|
+
* which correctly handles key names that contain dots or other JSONPath special characters.
|
|
757
|
+
*
|
|
758
|
+
* @method
|
|
759
|
+
* @param {string|string[]} path
|
|
760
|
+
* @returns {string}
|
|
761
|
+
* @private
|
|
762
|
+
*/
|
|
763
|
+
#normalizeJSONPath( path ) {
|
|
764
|
+
if ( Array.isArray( path ) ) {
|
|
765
|
+
return "$" + path.map( ( segment ) => `["${ String( segment ).replace( /\\/g, "\\\\" ).replace( /"/g, '\\"' ) }"]` ).join( "" );
|
|
766
|
+
}
|
|
767
|
+
return ( path.startsWith( "$" ) === false ) ? ( "$." + path ) : path;
|
|
768
|
+
}
|
|
769
|
+
|
|
724
770
|
}
|
|
725
771
|
|
|
726
772
|
const instance = new CommonMemoryCache();
|