eip-cloud-services 1.0.21 → 1.1.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 +28 -3
- package/README.md +386 -0
- package/package.json +3 -2
- package/src/cdn.js +11 -1
- package/src/lambda.js +0 -1
- package/src/mysql.js +11 -5
- package/src/redis.js +379 -132
- package/src/s3.js +145 -28
- package/src/util/log.js +3 -0
package/src/redis.js
CHANGED
|
@@ -1,26 +1,111 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
|
|
1
|
+
// Replace the redis require with ioredis
|
|
2
|
+
const Redis = require ( 'ioredis' );
|
|
3
|
+
const fs = require ( 'fs' );
|
|
4
|
+
let config = {};
|
|
5
|
+
const configDirPath = `${process.cwd ()}/config`;
|
|
6
|
+
if ( fs.existsSync ( configDirPath ) && fs.statSync ( configDirPath ).isDirectory () ) {
|
|
7
|
+
config = require ( 'config' ); // require the config directory if it exists
|
|
8
|
+
}
|
|
4
9
|
|
|
5
|
-
const
|
|
10
|
+
const clients = {};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates or retrieves a Redis client instance based on a given client identifier.
|
|
14
|
+
* If the client does not exist, it creates a new one, either connecting to a Redis Cluster
|
|
15
|
+
* or a single Redis instance based on the configuration.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} [clientId='main'] - The identifier for the Redis client. Defaults to 'main'.
|
|
18
|
+
* This identifier is used to manage multiple Redis client instances.
|
|
19
|
+
* @returns {Promise<Redis | Redis.Cluster>} A promise that resolves with the Redis client instance.
|
|
20
|
+
* @throws {Error} Throws an error if the Redis connection or configuration fails.
|
|
21
|
+
*
|
|
22
|
+
* @description
|
|
23
|
+
* This function manages a pool of Redis clients, identified by unique clientIds.
|
|
24
|
+
* It supports connecting to both standard Redis and Redis Cluster configurations.
|
|
25
|
+
* For a Redis Cluster, it expects an array of node details in the configuration.
|
|
26
|
+
* The function handles connection readiness and errors for both cluster and standard modes.
|
|
27
|
+
*/
|
|
28
|
+
const getClient = async ( clientId = 'main' ) => {
|
|
6
29
|
try {
|
|
7
|
-
if ( !
|
|
8
|
-
redisClient
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
30
|
+
if ( !clients[ clientId ] ) {
|
|
31
|
+
let redisClient;
|
|
32
|
+
|
|
33
|
+
if ( config?.redis?.clusterEnabled && Array.isArray ( config.redis.cluster ) && config.redis.cluster.length > 0 ) {
|
|
34
|
+
const clusterNodes = config.redis.cluster.map ( node => ( {
|
|
35
|
+
host: node.host,
|
|
36
|
+
port: node.port
|
|
37
|
+
} ) );
|
|
38
|
+
|
|
39
|
+
redisClient = new Redis.Cluster ( clusterNodes );
|
|
40
|
+
|
|
41
|
+
// Await until the cluster is ready
|
|
42
|
+
await new Promise ( ( resolve, reject ) => {
|
|
43
|
+
redisClient.once ( 'ready', resolve );
|
|
44
|
+
redisClient.once ( 'error', reject );
|
|
45
|
+
} );
|
|
46
|
+
|
|
47
|
+
redisClient.on ( 'node error', err => {
|
|
48
|
+
console.error ( 'Redis cluster node error', err );
|
|
49
|
+
} );
|
|
50
|
+
}
|
|
51
|
+
else if ( config?.redis?.clusterEnabled && ( !Array.isArray ( config.redis.cluster ) || config.redis.cluster.length === 0 ) ) {
|
|
52
|
+
throw new Error ( 'Redis Cluster is enabled but there were no cluster nodes defined in config.redis.cluster' );
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
redisClient = new Redis ( {
|
|
56
|
+
host: config?.redis?.host,
|
|
57
|
+
port: config?.redis?.port
|
|
58
|
+
} );
|
|
59
|
+
|
|
60
|
+
redisClient.on ( 'error', error => {
|
|
61
|
+
console.error ( '\x1b[33mREDIS CONNECTION FAILED: Redis connection failed. If you\'re running locally, is a redis server actually active? Also, check your connection configuration.\x1b[0m' );
|
|
62
|
+
throw error;
|
|
63
|
+
} );
|
|
64
|
+
|
|
65
|
+
await new Promise ( ( resolve, reject ) => {
|
|
66
|
+
redisClient.once ( 'ready', resolve );
|
|
67
|
+
redisClient.once ( 'error', reject );
|
|
68
|
+
} );
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
clients[ clientId ] = redisClient;
|
|
15
72
|
}
|
|
16
73
|
|
|
17
|
-
return
|
|
74
|
+
return clients[ clientId ];
|
|
18
75
|
}
|
|
19
|
-
catch ( error ){
|
|
20
|
-
throw
|
|
76
|
+
catch ( error ) {
|
|
77
|
+
throw error;
|
|
21
78
|
}
|
|
22
79
|
};
|
|
23
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Retrieves a Redis client based on the provided identifier.
|
|
83
|
+
* This function is primarily used internally within the module.
|
|
84
|
+
* For standard operations, the module's functionality should be used directly.
|
|
85
|
+
*
|
|
86
|
+
* @param {string} [clientId='main'] - The identifier for the Redis client. Defaults to 'main'.
|
|
87
|
+
* @returns {Promise<Redis>} - A promise that resolves with the Redis client.
|
|
88
|
+
*/
|
|
89
|
+
exports.getClient = getClient;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Retrieves a dedicated Redis client for subscription operations.
|
|
93
|
+
* This is a specialized client intended for internal use by the module,
|
|
94
|
+
* specifically for managing subscriptions to Redis channels.
|
|
95
|
+
*
|
|
96
|
+
* @returns {Promise<Redis>} - A promise that resolves with the Redis subscription client.
|
|
97
|
+
*/
|
|
98
|
+
exports.getSubClient = () => getClient ( 'main_sub' );
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Retrieves a dedicated Redis client for publishing operations.
|
|
102
|
+
* This client is used internally by the module for publishing messages to Redis channels.
|
|
103
|
+
* It's not intended for direct use; instead, use the module's publish functionality.
|
|
104
|
+
*
|
|
105
|
+
* @returns {Promise<Redis>} - A promise that resolves with the Redis publishing client.
|
|
106
|
+
*/
|
|
107
|
+
exports.getPubClient = () => getClient ( 'main_pub' );
|
|
108
|
+
|
|
24
109
|
/**
|
|
25
110
|
* Retrieves all keys matching a pattern.
|
|
26
111
|
* @param {string} pattern - The pattern to match.
|
|
@@ -34,11 +119,10 @@ exports.keys = async ( pattern ) => {
|
|
|
34
119
|
if ( typeof pattern === 'string' ) {
|
|
35
120
|
const client = await getClient ();
|
|
36
121
|
|
|
37
|
-
const
|
|
38
|
-
pattern.startsWith ( config.redis.prefix ) ? pattern : config.redis.prefix + pattern,
|
|
39
|
-
];
|
|
122
|
+
const fullPattern = pattern.startsWith ( config?.redis?.prefix ) ? pattern : config?.redis?.prefix + pattern;
|
|
40
123
|
|
|
41
|
-
|
|
124
|
+
// Use the keys method directly instead of sendCommand
|
|
125
|
+
return await client.keys ( fullPattern );
|
|
42
126
|
}
|
|
43
127
|
|
|
44
128
|
throw new Error ( `redis.keys expects a string pattern, instead the type provided was: ${typeof pattern}` );
|
|
@@ -49,6 +133,36 @@ exports.keys = async ( pattern ) => {
|
|
|
49
133
|
}
|
|
50
134
|
};
|
|
51
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Iteratively scans through keys in the Redis database.
|
|
138
|
+
* @param {number} cursor - The cursor to start scanning from. Use 0 to start a new scan.
|
|
139
|
+
* @param {string} [matchPattern='*'] - The pattern to match keys against. Defaults to '*' to match all keys.
|
|
140
|
+
* @param {number} [count=100] - The number of keys to return per call. Defaults to 100.
|
|
141
|
+
* @returns {Promise<Array>} - A promise that resolves with an array containing the next cursor and an array of keys.
|
|
142
|
+
*
|
|
143
|
+
* @description
|
|
144
|
+
* This method uses the SCAN command to iteratively scan through the keys in the Redis database.
|
|
145
|
+
* It allows for efficient scanning of large datasets without the risk of blocking the server for a long time.
|
|
146
|
+
* The method returns a promise that resolves with an array, where the first element is the next cursor to be used
|
|
147
|
+
* for subsequent calls, and the second element is an array of keys that matched the pattern.
|
|
148
|
+
*/
|
|
149
|
+
exports.scan = async ( cursor, matchPattern = '*', count = 100 ) => {
|
|
150
|
+
try {
|
|
151
|
+
const client = await getClient ();
|
|
152
|
+
|
|
153
|
+
const fullMatchPattern = matchPattern.startsWith ( config?.redis?.prefix ) ? matchPattern : config?.redis?.prefix + matchPattern;
|
|
154
|
+
|
|
155
|
+
// Directly use the scan method provided by ioredis
|
|
156
|
+
const result = await client.scan ( cursor, 'MATCH', fullMatchPattern, 'COUNT', count );
|
|
157
|
+
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
catch ( error ) {
|
|
161
|
+
console.log ( 'REDIS LIB ERROR [scan]', error );
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
52
166
|
/**
|
|
53
167
|
* Retrieves the value of a key.
|
|
54
168
|
* @param {string} key - The key to retrieve.
|
|
@@ -63,11 +177,10 @@ exports.get = async ( key ) => {
|
|
|
63
177
|
if ( typeof key === 'string' ) {
|
|
64
178
|
const client = await getClient ();
|
|
65
179
|
|
|
66
|
-
const
|
|
67
|
-
key.startsWith ( config.redis.prefix ) ? key : config.redis.prefix + key,
|
|
68
|
-
];
|
|
180
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
69
181
|
|
|
70
|
-
|
|
182
|
+
// Use the get method directly
|
|
183
|
+
const data = await client.get ( fullKey );
|
|
71
184
|
|
|
72
185
|
try {
|
|
73
186
|
return JSON.parse ( data );
|
|
@@ -80,7 +193,44 @@ exports.get = async ( key ) => {
|
|
|
80
193
|
throw new Error ( `redis.get expects a string key, instead the type provided was: ${typeof key}` );
|
|
81
194
|
}
|
|
82
195
|
catch ( error ) {
|
|
83
|
-
console.log ( 'REDIS LIB ERROR [get]', error
|
|
196
|
+
console.log ( 'REDIS LIB ERROR [get]', error );
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Retrieves the values of multiple keys.
|
|
203
|
+
* @param {string[]} keys - The keys to retrieve.
|
|
204
|
+
* @returns {Promise} - A promise that resolves with the values of the keys.
|
|
205
|
+
*
|
|
206
|
+
* @description This method retrieves the values associated with the specified keys from Redis.
|
|
207
|
+
* If the value is a JSON string, it will be parsed and returned as a JavaScript object.
|
|
208
|
+
* If the value is not a valid JSON string, it will be returned as a string.
|
|
209
|
+
*/
|
|
210
|
+
exports.multiGet = async ( keys ) => {
|
|
211
|
+
try {
|
|
212
|
+
if ( Array.isArray ( keys ) ) {
|
|
213
|
+
const client = await getClient ();
|
|
214
|
+
|
|
215
|
+
const fullKeys = keys.map ( key => key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key );
|
|
216
|
+
|
|
217
|
+
// Use the mget method directly
|
|
218
|
+
const data = await client.mget ( ...fullKeys );
|
|
219
|
+
|
|
220
|
+
return data.map ( val => {
|
|
221
|
+
try {
|
|
222
|
+
return JSON.parse ( val );
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return val;
|
|
226
|
+
}
|
|
227
|
+
} );
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
throw new Error ( `redis.multiGet expects an array of keys, instead the type provided was: ${typeof keys}` );
|
|
231
|
+
}
|
|
232
|
+
catch ( error ) {
|
|
233
|
+
console.log ( 'REDIS LIB ERROR [multiGet]', error );
|
|
84
234
|
throw error;
|
|
85
235
|
}
|
|
86
236
|
};
|
|
@@ -102,15 +252,12 @@ exports.set = async ( key, value, ex, px ) => {
|
|
|
102
252
|
if ( typeof key === 'string' ) {
|
|
103
253
|
const client = await getClient ();
|
|
104
254
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
];
|
|
109
|
-
|
|
110
|
-
if ( ex ) commandArgs.push ( 'EX', String ( ex ) );
|
|
111
|
-
if ( px ) commandArgs.push ( 'PX', String ( px ) );
|
|
255
|
+
// Automatically convert objects or arrays to JSON strings
|
|
256
|
+
const serializedValue = ( typeof value === 'object' && value !== null ) ? JSON.stringify ( value ) : value;
|
|
257
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
112
258
|
|
|
113
|
-
|
|
259
|
+
// Use the set method directly with optional EX and PX parameters
|
|
260
|
+
return await client.set ( fullKey, serializedValue, ...( ex ? [ 'EX', ex ] : [] ), ...( px ? [ 'PX', px ] : [] ) );
|
|
114
261
|
}
|
|
115
262
|
|
|
116
263
|
throw new Error ( `redis.set expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -135,17 +282,47 @@ exports.del = async ( key ) => {
|
|
|
135
282
|
if ( typeof key === 'string' ) {
|
|
136
283
|
const client = await getClient ();
|
|
137
284
|
|
|
138
|
-
const
|
|
139
|
-
key.startsWith ( config.redis.prefix ) ? key : config.redis.prefix + key,
|
|
140
|
-
];
|
|
285
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
141
286
|
|
|
142
|
-
|
|
287
|
+
// Use the del method directly
|
|
288
|
+
return await client.del ( fullKey );
|
|
143
289
|
}
|
|
144
290
|
|
|
145
291
|
throw new Error ( `redis.del expects a string key, instead the type provided was: ${typeof key}` );
|
|
146
292
|
}
|
|
147
293
|
catch ( error ) {
|
|
148
|
-
console.log ( 'REDIS LIB ERROR [del]', error
|
|
294
|
+
console.log ( 'REDIS LIB ERROR [del]', error );
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Deletes multiple keys.
|
|
301
|
+
* @param {string[]} keys - The keys to delete.
|
|
302
|
+
* @returns {Promise<number>} - A promise that resolves with the count of keys deleted.
|
|
303
|
+
*
|
|
304
|
+
* @description
|
|
305
|
+
* This method deletes the specified keys from Redis.
|
|
306
|
+
* If a key does not exist, it is silently ignored. The function returns the count of keys actually deleted.
|
|
307
|
+
* If an array is empty or none of the keys exist, the function returns 0.
|
|
308
|
+
* Note: It's more efficient to delete multiple keys in one call than to use individual delete calls for each key.
|
|
309
|
+
*/
|
|
310
|
+
exports.multiDel = async ( keys ) => {
|
|
311
|
+
try {
|
|
312
|
+
if ( Array.isArray ( keys ) && keys.every ( key => typeof key === 'string' ) ) {
|
|
313
|
+
const client = await getClient ();
|
|
314
|
+
|
|
315
|
+
// Prepend the Redis prefix to each key if necessary
|
|
316
|
+
const fullKeys = keys.map ( key => key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key );
|
|
317
|
+
|
|
318
|
+
// Use the del method with multiple keys
|
|
319
|
+
return await client.del ( ...fullKeys );
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
throw new Error ( `redis.multiDel expects an array of string keys, instead the type provided was: ${typeof keys}` );
|
|
323
|
+
}
|
|
324
|
+
catch ( error ) {
|
|
325
|
+
console.log ( 'REDIS LIB ERROR [multiDel]', error );
|
|
149
326
|
throw error;
|
|
150
327
|
}
|
|
151
328
|
};
|
|
@@ -154,7 +331,7 @@ exports.del = async ( key ) => {
|
|
|
154
331
|
* Adds one or more members to a set.
|
|
155
332
|
* @param {string} key - The key of the set.
|
|
156
333
|
* @param {string|string[]} members - The member(s) to add to the set.
|
|
157
|
-
* @returns {Promise} - A promise that resolves with the
|
|
334
|
+
* @returns {Promise<number>} - A promise that resolves with the number of members that were added to the set.
|
|
158
335
|
*
|
|
159
336
|
* @description This method adds one or more members to the specified set in Redis.
|
|
160
337
|
* If the set does not exist, it will be created.
|
|
@@ -166,12 +343,11 @@ exports.setAdd = async ( key, members ) => {
|
|
|
166
343
|
if ( typeof key === 'string' ) {
|
|
167
344
|
const client = await getClient ();
|
|
168
345
|
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
...( Array.isArray ( members ) ? members : [ members ] ),
|
|
172
|
-
];
|
|
346
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
347
|
+
const membersArray = Array.isArray ( members ) ? members : [ members ];
|
|
173
348
|
|
|
174
|
-
|
|
349
|
+
// Use the sadd method directly
|
|
350
|
+
return await client.sadd ( fullKey, ...membersArray );
|
|
175
351
|
}
|
|
176
352
|
|
|
177
353
|
throw new Error ( `redis.setAdd expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -186,7 +362,7 @@ exports.setAdd = async ( key, members ) => {
|
|
|
186
362
|
* Removes one or more members from a set.
|
|
187
363
|
* @param {string} key - The key of the set.
|
|
188
364
|
* @param {string|string[]} members - The member(s) to remove from the set.
|
|
189
|
-
* @returns {Promise} - A promise that resolves with the
|
|
365
|
+
* @returns {Promise<number>} - A promise that resolves with the number of members that were removed from the set.
|
|
190
366
|
*
|
|
191
367
|
* @description This method removes one or more members from the specified set in Redis.
|
|
192
368
|
* If the set does not exist or if any member does not exist in the set, it will be ignored.
|
|
@@ -197,18 +373,17 @@ exports.setRemove = async ( key, members ) => {
|
|
|
197
373
|
if ( typeof key === 'string' ) {
|
|
198
374
|
const client = await getClient ();
|
|
199
375
|
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
...( Array.isArray ( members ) ? members : [ members ] ),
|
|
203
|
-
];
|
|
376
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
377
|
+
const membersArray = Array.isArray ( members ) ? members : [ members ];
|
|
204
378
|
|
|
205
|
-
|
|
379
|
+
// Use the srem method directly
|
|
380
|
+
return await client.srem ( fullKey, ...membersArray );
|
|
206
381
|
}
|
|
207
382
|
|
|
208
383
|
throw new Error ( `redis.setRemove expects a string key, instead the type provided was: ${typeof key}` );
|
|
209
384
|
}
|
|
210
385
|
catch ( error ) {
|
|
211
|
-
console.log ( 'REDIS LIB ERROR [setRemove]', error
|
|
386
|
+
console.log ( 'REDIS LIB ERROR [setRemove]', error );
|
|
212
387
|
throw error;
|
|
213
388
|
}
|
|
214
389
|
};
|
|
@@ -216,7 +391,7 @@ exports.setRemove = async ( key, members ) => {
|
|
|
216
391
|
/**
|
|
217
392
|
* Retrieves all members of a set.
|
|
218
393
|
* @param {string} key - The key of the set.
|
|
219
|
-
* @returns {Promise} - A promise that resolves with
|
|
394
|
+
* @returns {Promise<string[]>} - A promise that resolves with an array of members of the set.
|
|
220
395
|
*
|
|
221
396
|
* @description This method retrieves all members of the specified set in Redis.
|
|
222
397
|
* If the set does not exist, it will return an empty array.
|
|
@@ -226,17 +401,16 @@ exports.setMembers = async ( key ) => {
|
|
|
226
401
|
if ( typeof key === 'string' ) {
|
|
227
402
|
const client = await getClient ();
|
|
228
403
|
|
|
229
|
-
const
|
|
230
|
-
key.startsWith ( config.redis.prefix ) ? key : config.redis.prefix + key,
|
|
231
|
-
];
|
|
404
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
232
405
|
|
|
233
|
-
|
|
406
|
+
// Use the smembers method directly
|
|
407
|
+
return await client.smembers ( fullKey );
|
|
234
408
|
}
|
|
235
409
|
|
|
236
410
|
throw new Error ( `redis.setMembers expects a string key, instead the type provided was: ${typeof key}` );
|
|
237
411
|
}
|
|
238
412
|
catch ( error ) {
|
|
239
|
-
console.log ( 'REDIS LIB ERROR [setMembers]', error
|
|
413
|
+
console.log ( 'REDIS LIB ERROR [setMembers]', error );
|
|
240
414
|
throw error;
|
|
241
415
|
}
|
|
242
416
|
};
|
|
@@ -244,7 +418,7 @@ exports.setMembers = async ( key ) => {
|
|
|
244
418
|
/**
|
|
245
419
|
* Removes and returns a random member from a set.
|
|
246
420
|
* @param {string} key - The key of the set.
|
|
247
|
-
* @returns {Promise} - A promise that resolves with the removed member, or null if the set is empty.
|
|
421
|
+
* @returns {Promise<string|null>} - A promise that resolves with the removed member, or null if the set is empty.
|
|
248
422
|
*
|
|
249
423
|
* @description
|
|
250
424
|
* This function removes and returns a random member from a set identified by the provided key.
|
|
@@ -256,25 +430,24 @@ exports.setPop = async ( key ) => {
|
|
|
256
430
|
try {
|
|
257
431
|
if ( typeof key === 'string' ) {
|
|
258
432
|
const client = await getClient ();
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
433
|
+
|
|
434
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
435
|
+
|
|
436
|
+
// Use the spop method directly
|
|
437
|
+
const member = await client.spop ( fullKey );
|
|
438
|
+
|
|
266
439
|
// If the member is null or an empty string, return null
|
|
267
440
|
if ( member === null || member === '' ) {
|
|
268
441
|
return null;
|
|
269
442
|
}
|
|
270
|
-
|
|
443
|
+
|
|
271
444
|
return member;
|
|
272
445
|
}
|
|
273
|
-
|
|
446
|
+
|
|
274
447
|
throw new Error ( `redis.setPop expects a string key, instead the type provided was: ${typeof key}` );
|
|
275
448
|
}
|
|
276
449
|
catch ( error ) {
|
|
277
|
-
console.log ( 'REDIS LIB ERROR [setPop]', error
|
|
450
|
+
console.log ( 'REDIS LIB ERROR [setPop]', error );
|
|
278
451
|
throw error;
|
|
279
452
|
}
|
|
280
453
|
};
|
|
@@ -283,7 +456,7 @@ exports.setPop = async ( key ) => {
|
|
|
283
456
|
* Prepends multiple values to the head of a list.
|
|
284
457
|
* @param {string} key - The key of the list.
|
|
285
458
|
* @param {string|string[]} values - The values to prepend to the list.
|
|
286
|
-
* @returns {Promise} - A promise that resolves with the
|
|
459
|
+
* @returns {Promise<number>} - A promise that resolves with the length of the list after the prepend operation.
|
|
287
460
|
*
|
|
288
461
|
* @description This method prepends one or more values to the head of the specified list in Redis.
|
|
289
462
|
* If the list does not exist, it will be created.
|
|
@@ -295,27 +468,17 @@ exports.listUnshift = async ( key, values ) => {
|
|
|
295
468
|
if ( typeof key === 'string' ) {
|
|
296
469
|
const client = await getClient ();
|
|
297
470
|
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
];
|
|
301
|
-
|
|
302
|
-
if ( typeof values === 'string' ) {
|
|
303
|
-
commandArgs.push ( values );
|
|
304
|
-
}
|
|
305
|
-
else if ( Array.isArray ( values ) ) {
|
|
306
|
-
commandArgs.push ( ...values );
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
309
|
-
throw new Error ( `redis.listUnshift expects a string or an array of strings as the values, instead the type provided was: ${typeof values}` );
|
|
310
|
-
}
|
|
471
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
472
|
+
const valuesArray = Array.isArray ( values ) ? values : [ values ];
|
|
311
473
|
|
|
312
|
-
|
|
474
|
+
// Use the lpush method directly
|
|
475
|
+
return await client.lpush ( fullKey, ...valuesArray );
|
|
313
476
|
}
|
|
314
477
|
|
|
315
478
|
throw new Error ( `redis.listUnshift expects a string key, instead the type provided was: ${typeof key}` );
|
|
316
479
|
}
|
|
317
480
|
catch ( error ) {
|
|
318
|
-
console.log ( 'REDIS LIB ERROR [listUnshift]', error
|
|
481
|
+
console.log ( 'REDIS LIB ERROR [listUnshift]', error );
|
|
319
482
|
throw error;
|
|
320
483
|
}
|
|
321
484
|
};
|
|
@@ -324,7 +487,7 @@ exports.listUnshift = async ( key, values ) => {
|
|
|
324
487
|
* Pushes values to the tail of a list.
|
|
325
488
|
* @param {string} key - The key of the list.
|
|
326
489
|
* @param {string|string[]} values - The value(s) to push to the list.
|
|
327
|
-
* @returns {Promise} - A promise that resolves with the
|
|
490
|
+
* @returns {Promise<number>} - A promise that resolves with the length of the list after the push operation.
|
|
328
491
|
*
|
|
329
492
|
* @description This method pushes one or more values to the tail of the specified list in Redis.
|
|
330
493
|
* If the list does not exist, it will be created.
|
|
@@ -336,27 +499,17 @@ exports.listPush = async ( key, values ) => {
|
|
|
336
499
|
if ( typeof key === 'string' ) {
|
|
337
500
|
const client = await getClient ();
|
|
338
501
|
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
];
|
|
502
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
503
|
+
const valuesArray = Array.isArray ( values ) ? values : [ values ];
|
|
342
504
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
else if ( Array.isArray ( values ) ) {
|
|
347
|
-
commandArgs.push ( ...values );
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
throw new Error ( `redis.listPush expects a string or an array of strings as the values, instead the type provided was: ${typeof values}` );
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
return await client.sendCommand ( [ 'RPUSH', ...commandArgs ] );
|
|
505
|
+
// Use the rpush method directly
|
|
506
|
+
return await client.rpush ( fullKey, ...valuesArray );
|
|
354
507
|
}
|
|
355
508
|
|
|
356
509
|
throw new Error ( `redis.listPush expects a string key, instead the type provided was: ${typeof key}` );
|
|
357
510
|
}
|
|
358
511
|
catch ( error ) {
|
|
359
|
-
console.log ( 'REDIS LIB ERROR [listPush]', error
|
|
512
|
+
console.log ( 'REDIS LIB ERROR [listPush]', error );
|
|
360
513
|
throw error;
|
|
361
514
|
}
|
|
362
515
|
};
|
|
@@ -364,8 +517,8 @@ exports.listPush = async ( key, values ) => {
|
|
|
364
517
|
/**
|
|
365
518
|
* Removes and returns the first element of a list.
|
|
366
519
|
* @param {string} key - The key of the list.
|
|
367
|
-
* @param {number} count - The number of items to remove (default:
|
|
368
|
-
* @returns {Promise} - A promise that resolves with the
|
|
520
|
+
* @param {number} count - The number of items to remove (default: 1).
|
|
521
|
+
* @returns {Promise<string|string[]>} - A promise that resolves with the removed element(s).
|
|
369
522
|
*
|
|
370
523
|
* @description This method removes and returns the first element(s) from the specified list in Redis.
|
|
371
524
|
* If the list is empty or does not exist, it will return null.
|
|
@@ -377,18 +530,41 @@ exports.listPop = async ( key, count = 1 ) => {
|
|
|
377
530
|
if ( typeof key === 'string' ) {
|
|
378
531
|
const client = await getClient ();
|
|
379
532
|
|
|
380
|
-
const
|
|
381
|
-
key.startsWith ( config.redis.prefix ) ? key : config.redis.prefix + key,
|
|
382
|
-
String ( count ),
|
|
383
|
-
];
|
|
533
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
384
534
|
|
|
385
|
-
|
|
535
|
+
// Use the lpop method directly with the count parameter
|
|
536
|
+
return await client.lpop ( fullKey, count );
|
|
386
537
|
}
|
|
387
538
|
|
|
388
539
|
throw new Error ( `redis.listPop expects a string key, instead the type provided was: ${typeof key}` );
|
|
389
540
|
}
|
|
390
541
|
catch ( error ) {
|
|
391
|
-
console.log ( 'REDIS LIB ERROR [listPop]', error
|
|
542
|
+
console.log ( 'REDIS LIB ERROR [listPop]', error );
|
|
543
|
+
throw error;
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Removes and returns the last element of a list.
|
|
549
|
+
* @param {string} key - The key of the list.
|
|
550
|
+
* @returns {Promise<string|null>} - A promise that resolves with the removed element, or null if the list is empty.
|
|
551
|
+
*
|
|
552
|
+
* @description This method removes and returns the last element from the specified list in Redis.
|
|
553
|
+
*/
|
|
554
|
+
exports.listPopEnd = async ( key ) => {
|
|
555
|
+
try {
|
|
556
|
+
if ( typeof key === 'string' ) {
|
|
557
|
+
const client = await getClient ();
|
|
558
|
+
|
|
559
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
560
|
+
|
|
561
|
+
return await client.rpop ( fullKey );
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
throw new Error ( 'redis.listPopEnd expects a string key' );
|
|
565
|
+
}
|
|
566
|
+
catch ( error ) {
|
|
567
|
+
console.error ( 'REDIS LIB ERROR [listPopEnd]', error );
|
|
392
568
|
throw error;
|
|
393
569
|
}
|
|
394
570
|
};
|
|
@@ -398,7 +574,7 @@ exports.listPop = async ( key, count = 1 ) => {
|
|
|
398
574
|
* @param {string} key - The key of the list.
|
|
399
575
|
* @param {number} start - The starting index (default: 0).
|
|
400
576
|
* @param {number} end - The ending index (default: -1).
|
|
401
|
-
* @returns {Promise} - A promise that resolves with
|
|
577
|
+
* @returns {Promise<string[]>} - A promise that resolves with an array of elements from the specified range.
|
|
402
578
|
*
|
|
403
579
|
* @description This method retrieves a range of elements from the specified list in Redis.
|
|
404
580
|
* The range is specified by the start and end indices.
|
|
@@ -410,19 +586,16 @@ exports.listRange = async ( key, start = 0, end = -1 ) => {
|
|
|
410
586
|
if ( typeof key === 'string' ) {
|
|
411
587
|
const client = await getClient ();
|
|
412
588
|
|
|
413
|
-
const
|
|
414
|
-
key.startsWith ( config.redis.prefix ) ? key : config.redis.prefix + key,
|
|
415
|
-
String ( start ),
|
|
416
|
-
String ( end ),
|
|
417
|
-
];
|
|
589
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
418
590
|
|
|
419
|
-
|
|
591
|
+
// Use the lrange method directly
|
|
592
|
+
return await client.lrange ( fullKey, start, end );
|
|
420
593
|
}
|
|
421
594
|
|
|
422
595
|
throw new Error ( `redis.listRange expects a string key, instead the type provided was: ${typeof key}` );
|
|
423
596
|
}
|
|
424
597
|
catch ( error ) {
|
|
425
|
-
console.log ( 'REDIS LIB ERROR [listRange]', error
|
|
598
|
+
console.log ( 'REDIS LIB ERROR [listRange]', error );
|
|
426
599
|
throw error;
|
|
427
600
|
}
|
|
428
601
|
};
|
|
@@ -430,7 +603,7 @@ exports.listRange = async ( key, start = 0, end = -1 ) => {
|
|
|
430
603
|
/**
|
|
431
604
|
* Retrieves the expiration time of a key in seconds.
|
|
432
605
|
* @param {string} key - The key to get the expiration time of.
|
|
433
|
-
* @returns {Promise} - A promise that resolves with the
|
|
606
|
+
* @returns {Promise<number>} - A promise that resolves with the number of seconds remaining until the key expires, or -1 if the key does not have an expiration.
|
|
434
607
|
*
|
|
435
608
|
* @description This method retrieves the expiration time (in seconds) of the specified key in Redis.
|
|
436
609
|
* If the key does not exist or does not have an expiration set, it will return -1.
|
|
@@ -442,17 +615,16 @@ exports.getExpiryInSeconds = async ( key ) => {
|
|
|
442
615
|
if ( typeof key === 'string' ) {
|
|
443
616
|
const client = await getClient ();
|
|
444
617
|
|
|
445
|
-
const
|
|
446
|
-
key.startsWith ( config.redis.prefix ) ? key : config.redis.prefix + key,
|
|
447
|
-
];
|
|
618
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
448
619
|
|
|
449
|
-
|
|
620
|
+
// Use the ttl method directly
|
|
621
|
+
return await client.ttl ( fullKey );
|
|
450
622
|
}
|
|
451
623
|
|
|
452
624
|
throw new Error ( `redis.getExpiryInSeconds expects a string key, instead the type provided was: ${typeof key}` );
|
|
453
625
|
}
|
|
454
626
|
catch ( error ) {
|
|
455
|
-
console.log ( 'REDIS LIB ERROR [getExpiryInSeconds]', error
|
|
627
|
+
console.log ( 'REDIS LIB ERROR [getExpiryInSeconds]', error );
|
|
456
628
|
throw error;
|
|
457
629
|
}
|
|
458
630
|
};
|
|
@@ -461,7 +633,7 @@ exports.getExpiryInSeconds = async ( key ) => {
|
|
|
461
633
|
* Sets the expiration time for a key in seconds.
|
|
462
634
|
* @param {string} key - The key to set the expiration time for.
|
|
463
635
|
* @param {number} seconds - The expiration time in seconds (default: 0).
|
|
464
|
-
* @returns {Promise} - A promise that resolves with the
|
|
636
|
+
* @returns {Promise<number>} - A promise that resolves with 1 if the expiration time was set successfully, or 0 if the key does not exist.
|
|
465
637
|
*
|
|
466
638
|
* @description This method sets the expiration time (in seconds) for the specified key in Redis.
|
|
467
639
|
* If the key does not exist, it will return 0 indicating no expiration was set.
|
|
@@ -472,25 +644,100 @@ exports.setExpiry = async ( key, seconds = 0 ) => {
|
|
|
472
644
|
if ( typeof key === 'string' ) {
|
|
473
645
|
const client = await getClient ();
|
|
474
646
|
|
|
475
|
-
const
|
|
476
|
-
key.startsWith ( config.redis.prefix ) ? key : config.redis.prefix + key,
|
|
477
|
-
String ( seconds ),
|
|
478
|
-
];
|
|
647
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
479
648
|
|
|
480
|
-
|
|
649
|
+
// Use the expire method directly
|
|
650
|
+
return await client.expire ( fullKey, seconds );
|
|
481
651
|
}
|
|
482
652
|
|
|
483
653
|
throw new Error ( `redis.setExpiry expects a string key, instead the type provided was: ${typeof key}` );
|
|
484
654
|
}
|
|
485
655
|
catch ( error ) {
|
|
486
|
-
console.log ( 'REDIS LIB ERROR [setExpiry]', error
|
|
656
|
+
console.log ( 'REDIS LIB ERROR [setExpiry]', error );
|
|
487
657
|
throw error;
|
|
488
658
|
}
|
|
489
659
|
};
|
|
490
660
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
661
|
+
/**
|
|
662
|
+
* Publishes a message to a channel.
|
|
663
|
+
* @param {string} channel - The channel to publish the message to.
|
|
664
|
+
* @param {string} message - The message to publish.
|
|
665
|
+
* @returns {Promise<number>} - A promise that resolves with the number of subscribers that received the message.
|
|
666
|
+
*
|
|
667
|
+
* @description This method publishes a message to the specified channel in Redis.
|
|
668
|
+
*/
|
|
669
|
+
exports.publish = async ( channel, message ) => {
|
|
670
|
+
try {
|
|
671
|
+
if ( typeof channel === 'string' && typeof message === 'string' ) {
|
|
672
|
+
const client = await getClient ( `${channel}_pub` );
|
|
494
673
|
|
|
495
|
-
|
|
674
|
+
return client.publish ( channel, message );
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
throw new Error ( 'redis.publish expects string types for both channel and message' );
|
|
678
|
+
}
|
|
679
|
+
catch ( error ) {
|
|
680
|
+
console.error ( 'REDIS LIB ERROR [publish]', error );
|
|
681
|
+
throw error;
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Subscribes to a channel to listen for messages.
|
|
687
|
+
* @param {string} channel - The channel to subscribe to.
|
|
688
|
+
* @param {Function} messageHandler - The callback function to handle messages.
|
|
689
|
+
* @returns {Promise<void>} - A promise that resolves when the subscription is set up.
|
|
690
|
+
*
|
|
691
|
+
* @description This method subscribes to the specified channel in Redis and sets up a handler for incoming messages.
|
|
692
|
+
*/
|
|
693
|
+
exports.subscribe = async ( channel, messageHandler ) => {
|
|
694
|
+
try {
|
|
695
|
+
if ( typeof channel === 'string' && typeof messageHandler === 'function' ) {
|
|
696
|
+
const client = await getClient ( `${channel}_sub` );
|
|
697
|
+
|
|
698
|
+
client.on ( 'message', ( receivedChannel, message ) => {
|
|
699
|
+
if ( receivedChannel === channel ) {
|
|
700
|
+
messageHandler ( message );
|
|
701
|
+
}
|
|
702
|
+
} );
|
|
703
|
+
await client.subscribe ( channel );
|
|
704
|
+
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
throw new Error ( 'redis.subscribe expects a string channel and a callback function' );
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
catch ( error ) {
|
|
712
|
+
console.error ( 'REDIS LIB ERROR [subscribe]', error );
|
|
713
|
+
throw error;
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Retrieves information and statistics about the Redis server.
|
|
719
|
+
* @returns {Promise<string>} - A promise that resolves with server information.
|
|
720
|
+
*
|
|
721
|
+
* @description This method returns information and various statistics about the Redis server.
|
|
722
|
+
*/
|
|
723
|
+
exports.info = async () => {
|
|
724
|
+
try {
|
|
725
|
+
const client = await getClient ();
|
|
726
|
+
|
|
727
|
+
return await client.info ();
|
|
728
|
+
}
|
|
729
|
+
catch ( error ) {
|
|
730
|
+
console.error ( 'REDIS LIB ERROR [info]', error );
|
|
731
|
+
throw error;
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Gracefully closes the Redis connection.
|
|
737
|
+
* @returns {Promise<void>} - A promise that resolves once the connection is closed.
|
|
738
|
+
*
|
|
739
|
+
* @description This method closes the Redis connection using the 'quit' command, ensuring a graceful shutdown of the connection.
|
|
740
|
+
*/
|
|
741
|
+
exports.kill = async () => {
|
|
742
|
+
await Promise.all ( Object.values ( clients ).map ( client => client.quit () ) );
|
|
496
743
|
};
|