eip-cloud-services 1.0.17 → 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 +29 -0
- package/README.md +386 -0
- package/package.json +2 -1
- package/src/mysql.js +1 -1
- package/src/redis.js +303 -130
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,36 @@
|
|
|
1
|
+
|
|
1
2
|
# Changelog
|
|
2
3
|
|
|
3
4
|
All notable changes to this project will be documented in this file.
|
|
4
5
|
|
|
6
|
+
## [1.1.0] - 2023-11-18
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- **Redis Module Major Overhaul:**
|
|
10
|
+
- Transitioned from using the node redis package to the ioredis package.
|
|
11
|
+
- Updated the `getClient` method to support Redis clusters, including handling of client connections in subscriber mode.
|
|
12
|
+
- Implemented a dictionary of connected clients for efficient client management in Redis.
|
|
13
|
+
- Added new functionalities to the Redis module, including handling for various Redis commands and pub/sub features.
|
|
14
|
+
- Enriched the module with JSDoc comments for better clarity and documentation.
|
|
15
|
+
- Created a comprehensive README for the Redis module, detailing its features and usage.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- **AWS S3 Module Developments:**
|
|
19
|
+
- Reviewed and discussed functionalities of the AWS S3 module.
|
|
20
|
+
- Created a README file for the AWS S3 module, detailing usage and configuration.
|
|
21
|
+
- **CDN Module Improvements:**
|
|
22
|
+
- Analyzed functionalities of the CDN module.
|
|
23
|
+
- Generated a README for the CDN module, including instructions on usage and examples.
|
|
24
|
+
- **MySQL Module Update:**
|
|
25
|
+
- Discussed the MySQL module's features and capabilities.
|
|
26
|
+
- Compiled a README for the MySQL module, outlining key functionalities and configuration.
|
|
27
|
+
- **AWS Lambda Module Revision:**
|
|
28
|
+
- Explored the AWS Lambda module's functionalities.
|
|
29
|
+
- Prepared a README for the AWS Lambda module, providing usage examples and details.
|
|
30
|
+
- **Overall Module Documentation:**
|
|
31
|
+
- Combined individual READMEs into a single comprehensive README file.
|
|
32
|
+
- Added a summary, installation and import guide, and example configuration to the combined README.
|
|
33
|
+
|
|
5
34
|
## [1.0.21] - 2023-06-21
|
|
6
35
|
|
|
7
36
|
### Fixed
|
package/README.md
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# EIP Cloud Services Module
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
The EIP Cloud Services Module is a comprehensive Node.js package that provides seamless integration with various cloud services, including Redis, AWS S3, CDN, AWS Lambda, and MySQL. This module is designed to simplify the complexities of interacting with these cloud services, offering a range of functionalities from data caching and storage to content delivery and serverless computing.
|
|
6
|
+
|
|
7
|
+
## Installation and Import
|
|
8
|
+
|
|
9
|
+
To use this module, first install it in your Node.js project. Then, import the required services as follows:
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
const { redis, cdn, mysql } = require('eip-cloud-services');
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Config Example
|
|
16
|
+
|
|
17
|
+
Here is an example configuration for the EIP Cloud Services Module. Replace the placeholder values with your actual configuration details.
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
const packageJson = require('../package.json');
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
cdn: {
|
|
24
|
+
['cdnName']: { // e.g. "myCdn"
|
|
25
|
+
['envName1']: { //e.g. "production"
|
|
26
|
+
type: 'google',
|
|
27
|
+
urlMapName: 'YOUR_GCP_URL_MAP_NAME',
|
|
28
|
+
projectId: 'YOUR_GCP_PROJECT_NAME',
|
|
29
|
+
},
|
|
30
|
+
['envName2']: { // e.g. "staging"
|
|
31
|
+
type: 'amazon',
|
|
32
|
+
distributionId: 'YOUR_DISTRIBUTION_ID',
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
redis: { // For regular redis connections
|
|
37
|
+
port: 'YOUR_REDIS_PORT',
|
|
38
|
+
host: 'YOUR_REDIS_HOST',
|
|
39
|
+
prefix: 'YOUR_REDIS_PREFIX',
|
|
40
|
+
},
|
|
41
|
+
redis: { // For redis cluster instances
|
|
42
|
+
prefix: 'YOUR_REDIS_PREFIX',
|
|
43
|
+
clusterEnabled: true,
|
|
44
|
+
cluster: [
|
|
45
|
+
{
|
|
46
|
+
port: 'YOUR_REDIS_PORT',
|
|
47
|
+
host: 'YOUR_REDIS_HOST',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
port: 'YOUR_REDIS_PORT_2',
|
|
51
|
+
host: 'YOUR_REDIS_HOST_2',
|
|
52
|
+
},
|
|
53
|
+
...
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
s3: {
|
|
57
|
+
Bucket: 'YOUR_S3_BUCKET',
|
|
58
|
+
logs: "verbose", // "verbose" or "outputs", any other value will not log. verbose will log all activity. outputs will only log when there is a file updated.
|
|
59
|
+
logsFunction: ( message ) => { ... } // Optional, if nothing is provided console.log will be used.
|
|
60
|
+
},
|
|
61
|
+
mysql: {
|
|
62
|
+
connectionLimit: 10, // Max connections
|
|
63
|
+
host: 'my-database.domain.com',
|
|
64
|
+
user: 'user',
|
|
65
|
+
password: 'password',
|
|
66
|
+
database: 'my-database', // defaults to undefined
|
|
67
|
+
multipleStatements: false // defaults to true if not set
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Table of Contents
|
|
73
|
+
|
|
74
|
+
1. [Redis Module](#redis-module)
|
|
75
|
+
2. [AWS S3 Module](#aws-s3-module)
|
|
76
|
+
3. [CDN Module](#cdn-module)
|
|
77
|
+
4. [MySQL Module](#mysql-module)
|
|
78
|
+
5. [AWS Lambda Module](#aws-lambda-module)
|
|
79
|
+
|
|
80
|
+
# AWS Lambda Module
|
|
81
|
+
|
|
82
|
+
## Overview
|
|
83
|
+
|
|
84
|
+
This module provides an interface for invoking AWS Lambda functions. It simplifies the process of triggering Lambda functions from your Node.js application, with support for both synchronous and asynchronous invocations.
|
|
85
|
+
|
|
86
|
+
## Installation
|
|
87
|
+
|
|
88
|
+
Ensure this module is included in your Node.js project. Import the Lambda component as follows:
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
const lambda = require('eip-cloud-services/lambda');
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Usage
|
|
95
|
+
|
|
96
|
+
### Invoking a Lambda Function
|
|
97
|
+
|
|
98
|
+
You can invoke a Lambda function by specifying the function name and the event payload. The module supports both waiting for the function execution to complete and fire-and-forget invocations.
|
|
99
|
+
|
|
100
|
+
#### Synchronous Invocation (Wait for Execution to start)
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
const response = await lambda.invokeLambda('yourFunctionName', { key: 'value' }, true);
|
|
104
|
+
console.log(response);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### Asynchronous Invocation (Fire-and-Forget)
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
await lambda.invokeLambda('yourFunctionName', { key: 'value' }, false);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Parameters
|
|
114
|
+
|
|
115
|
+
- `functionName`: The name of the Lambda function to invoke.
|
|
116
|
+
- `eventPayload`: The payload to pass to the function. This can be any valid JSON object.
|
|
117
|
+
- `waitForExecution` (optional): Set to `true` to wait for the execution to start and receive a response.
|
|
118
|
+
- `context` (optional): The client context for the function execution.
|
|
119
|
+
- `invocationType` (optional): Defaults to 'Event'. Can be set to 'RequestResponse' for synchronous execution.
|
|
120
|
+
- `logType` (optional): The type of logging for the function.
|
|
121
|
+
|
|
122
|
+
## Configuration
|
|
123
|
+
|
|
124
|
+
Configure the module with your AWS credentials and Lambda settings.
|
|
125
|
+
|
|
126
|
+
## Error Handling
|
|
127
|
+
|
|
128
|
+
The module includes error handling to manage issues related to Lambda invocation, such as network errors or configuration problems.
|
|
129
|
+
|
|
130
|
+
## Logging
|
|
131
|
+
|
|
132
|
+
Logging is provided to track the start and completion of Lambda invocations, aiding in debugging and monitoring.
|
|
133
|
+
|
|
134
|
+
# MySQL Module
|
|
135
|
+
|
|
136
|
+
## Overview
|
|
137
|
+
|
|
138
|
+
This MySQL module provides a simple and efficient interface for interacting with MySQL databases. It includes functionalities to manage database connections, execute queries, and handle connection pooling.
|
|
139
|
+
|
|
140
|
+
## Installation
|
|
141
|
+
|
|
142
|
+
Ensure this module is included in your Node.js project. Import the MySQL component as follows:
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
const mysql = require('eip-cloud-services/mysql');
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Usage
|
|
149
|
+
|
|
150
|
+
### Executing Queries
|
|
151
|
+
|
|
152
|
+
You can execute queries using the `query` method. This method automatically handles connections and releases them after query execution.
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
const results = await mysql.query('SELECT * FROM your_table');
|
|
156
|
+
console.log(results);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Manually Managing Database Connections
|
|
160
|
+
|
|
161
|
+
It's not required for you to get connections manually, you can use the methods directly without having to setup connections. Getting a connection should only be used if you need to parse the connection to a third party module for example.
|
|
162
|
+
|
|
163
|
+
#### Get a Connection Pool
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
const pool = mysql.getPool();
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### Get a Single Connection
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
const connection = await mysql.getConnection();
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
### Closing the Connection Pool
|
|
177
|
+
|
|
178
|
+
To gracefully close all connections in the pool:
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
await mysql.kill();
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Configuration
|
|
185
|
+
|
|
186
|
+
Configure your MySQL connection settings (like host, user, password, etc.) in the `config` directory.
|
|
187
|
+
|
|
188
|
+
## Error Handling
|
|
189
|
+
|
|
190
|
+
The module is designed to handle errors gracefully, providing clear error messages for database connection issues and query errors.
|
|
191
|
+
|
|
192
|
+
## Pooling
|
|
193
|
+
|
|
194
|
+
- The module uses connection pooling for efficient database interaction.
|
|
195
|
+
- The pool is automatically created and managed by the module.
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# CDN Module
|
|
199
|
+
|
|
200
|
+
## Overview
|
|
201
|
+
|
|
202
|
+
This module provides functionalities to manage and interact with Content Delivery Networks (CDNs) like Amazon CloudFront and Google Cloud CDN. It includes features for creating invalidations, thereby ensuring that the latest content is served to end-users.
|
|
203
|
+
|
|
204
|
+
## Installation
|
|
205
|
+
|
|
206
|
+
Ensure this module is included in your Node.js project. Import the CDN component as follows:
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
const cdn = require('eip-cloud-services/cdn');
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Usage
|
|
213
|
+
|
|
214
|
+
### Create a CDN Invalidation
|
|
215
|
+
|
|
216
|
+
To invalidate cached content in a CDN, use the `createInvalidation` method. This method supports invalidating content in both Amazon CloudFront and Google Cloud CDN.
|
|
217
|
+
|
|
218
|
+
#### Invalidate in Amazon CloudFront
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
await cdn.createInvalidation('amazon', 'path/to/your/file.jpg', 'production');
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
#### Invalidate in Google Cloud CDN
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
await cdn.createInvalidation('google', 'path/to/your/file.jpg', 'production');
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
You can also invalidate multiple paths by passing an array of keys:
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
await cdn.createInvalidation('amazon', ['file1.jpg', 'file2.jpg'], 'staging');
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Configuration
|
|
237
|
+
|
|
238
|
+
Configure the module with your CDN settings in the `config` directory. The configuration should include details like project ID, distribution ID, and URL map names for the respective CDNs.
|
|
239
|
+
|
|
240
|
+
## Error Handling
|
|
241
|
+
|
|
242
|
+
The module is equipped to handle errors gracefully, including validation of input parameters and handling CDN-specific errors.
|
|
243
|
+
|
|
244
|
+
## Advanced Features
|
|
245
|
+
|
|
246
|
+
- Supports both Amazon CloudFront and Google Cloud CDN.
|
|
247
|
+
- Validates the key argument to ensure proper formatting.
|
|
248
|
+
- Constructs invalidation paths based on the provided keys.
|
|
249
|
+
- Initializes Google Auth if Google CDN is used.
|
|
250
|
+
- Sends invalidation commands to the CDN client based on the type of CDN and environment.
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
# AWS S3 Module
|
|
254
|
+
|
|
255
|
+
## Overview
|
|
256
|
+
|
|
257
|
+
This module provides an interface for interacting with AWS S3, offering functionalities like object retrieval, storage, deletion, and more. It supports advanced features such as encryption and cache control directives, making it a versatile tool for managing S3 operations efficiently.
|
|
258
|
+
|
|
259
|
+
## Installation
|
|
260
|
+
|
|
261
|
+
Ensure this module is included in your Node.js project. Import the S3 component as follows:
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
const s3 = require('eip-cloud-services/s3');
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Usage
|
|
268
|
+
|
|
269
|
+
### Check if an Object Exists
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
const exists = await s3.exists('myObjectKey');
|
|
273
|
+
console.log(exists); // true if exists, false otherwise
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Retrieve an Object
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
const object = await s3.get('myObjectKey');
|
|
280
|
+
console.log(object);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Store an Object
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
await s3.set('myObjectKey', 'myObjectData', { /* options */ });
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Delete an Object
|
|
290
|
+
|
|
291
|
+
```javascript
|
|
292
|
+
await s3.del('myObjectKey');
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Copy an Object
|
|
296
|
+
|
|
297
|
+
```javascript
|
|
298
|
+
await s3.copy('sourceObjectKey', 'destinationObjectKey');
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Move an Object
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
await s3.move('sourceObjectKey', 'destinationObjectKey');
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Managing Cache-Control and Encryption
|
|
308
|
+
|
|
309
|
+
The module provides detailed control over cache behavior and supports encryption for stored objects, allowing you to optimize performance and security.
|
|
310
|
+
|
|
311
|
+
## Configuration
|
|
312
|
+
|
|
313
|
+
Configure the module with your AWS credentials and preferred settings in the `config` directory.
|
|
314
|
+
|
|
315
|
+
## Error Handling
|
|
316
|
+
|
|
317
|
+
The module includes comprehensive error handling, ensuring robust interaction with AWS S3 even in complex scenarios.
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
# Redis Module
|
|
322
|
+
|
|
323
|
+
## Overview
|
|
324
|
+
|
|
325
|
+
This Redis module provides a robust interface for interacting with Redis, supporting both standard Redis operations and advanced features like Redis Clusters. The module is designed to manage multiple Redis client instances efficiently, allowing seamless operation with different Redis configurations.
|
|
326
|
+
|
|
327
|
+
## Installation
|
|
328
|
+
|
|
329
|
+
To use this Redis module, first ensure that it is included in your Node.js project. You can import the module as follows:
|
|
330
|
+
|
|
331
|
+
```javascript
|
|
332
|
+
const redis = require('eip-cloud-services/redis');
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Usage
|
|
336
|
+
|
|
337
|
+
### Standard Redis Operations
|
|
338
|
+
|
|
339
|
+
You can perform standard Redis operations like setting, getting, deleting keys, etc. Here are some examples:
|
|
340
|
+
|
|
341
|
+
#### Set a Key
|
|
342
|
+
|
|
343
|
+
```javascript
|
|
344
|
+
await redis.set('myKey', 'myValue');
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
#### Get a Key
|
|
348
|
+
|
|
349
|
+
```javascript
|
|
350
|
+
const value = await redis.get('myKey');
|
|
351
|
+
console.log(value); // Outputs: myValue
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### Delete a Key
|
|
355
|
+
|
|
356
|
+
```javascript
|
|
357
|
+
await redis.del('myKey');
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Advanced Operations
|
|
361
|
+
|
|
362
|
+
#### Using Redis Cluster
|
|
363
|
+
|
|
364
|
+
If your Redis setup includes a cluster, the module automatically configures the client for cluster operations based on your configuration.
|
|
365
|
+
|
|
366
|
+
#### Subscribing to a Channel
|
|
367
|
+
|
|
368
|
+
```javascript
|
|
369
|
+
redis.subscribe('myChannel', (message) => {
|
|
370
|
+
console.log(`Received: ${message}`);
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### Publishing to a Channel
|
|
375
|
+
|
|
376
|
+
```javascript
|
|
377
|
+
await redis.publish('myChannel', 'Hello, World!');
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Managing Redis Clients
|
|
381
|
+
|
|
382
|
+
The module internally manages multiple Redis clients for different purposes (like separate clients for pub/sub). However, this is abstracted away from the standard use of the module.
|
|
383
|
+
|
|
384
|
+
## Error Handling
|
|
385
|
+
|
|
386
|
+
The module is designed to gracefully handle Redis errors, including connection issues and cluster errors.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eip-cloud-services",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Houses a collection of helpers for connecting with Cloud services.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"@aws-sdk/client-secrets-manager": "^3.354.0",
|
|
20
20
|
"config": "^3.3.9",
|
|
21
21
|
"google-auth-library": "^8.8.0",
|
|
22
|
+
"ioredis": "^5.3.2",
|
|
22
23
|
"mysql": "^2.18.1",
|
|
23
24
|
"redis": "^4.6.7"
|
|
24
25
|
}
|
package/src/mysql.js
CHANGED
package/src/redis.js
CHANGED
|
@@ -1,32 +1,110 @@
|
|
|
1
|
-
|
|
1
|
+
// Replace the redis require with ioredis
|
|
2
|
+
const Redis = require ( 'ioredis' );
|
|
2
3
|
const fs = require ( 'fs' );
|
|
3
4
|
let config = {};
|
|
4
|
-
const configDirPath = `${
|
|
5
|
+
const configDirPath = `${process.cwd ()}/config`;
|
|
5
6
|
if ( fs.existsSync ( configDirPath ) && fs.statSync ( configDirPath ).isDirectory () ) {
|
|
6
7
|
config = require ( 'config' ); // require the config directory if it exists
|
|
7
8
|
}
|
|
8
|
-
let redisClient;
|
|
9
9
|
|
|
10
|
-
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' ) => {
|
|
11
29
|
try {
|
|
12
|
-
if ( !
|
|
13
|
-
redisClient
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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;
|
|
20
72
|
}
|
|
21
73
|
|
|
22
|
-
return
|
|
74
|
+
return clients[ clientId ];
|
|
23
75
|
}
|
|
24
|
-
catch ( error ){
|
|
25
|
-
throw
|
|
76
|
+
catch ( error ) {
|
|
77
|
+
throw error;
|
|
26
78
|
}
|
|
27
79
|
};
|
|
28
80
|
|
|
29
|
-
|
|
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' );
|
|
30
108
|
|
|
31
109
|
/**
|
|
32
110
|
* Retrieves all keys matching a pattern.
|
|
@@ -41,11 +119,10 @@ exports.keys = async ( pattern ) => {
|
|
|
41
119
|
if ( typeof pattern === 'string' ) {
|
|
42
120
|
const client = await getClient ();
|
|
43
121
|
|
|
44
|
-
const
|
|
45
|
-
pattern.startsWith ( config?.redis?.prefix ) ? pattern : config?.redis?.prefix + pattern,
|
|
46
|
-
];
|
|
122
|
+
const fullPattern = pattern.startsWith ( config?.redis?.prefix ) ? pattern : config?.redis?.prefix + pattern;
|
|
47
123
|
|
|
48
|
-
|
|
124
|
+
// Use the keys method directly instead of sendCommand
|
|
125
|
+
return await client.keys ( fullPattern );
|
|
49
126
|
}
|
|
50
127
|
|
|
51
128
|
throw new Error ( `redis.keys expects a string pattern, instead the type provided was: ${typeof pattern}` );
|
|
@@ -73,13 +150,12 @@ exports.scan = async ( cursor, matchPattern = '*', count = 100 ) => {
|
|
|
73
150
|
try {
|
|
74
151
|
const client = await getClient ();
|
|
75
152
|
|
|
76
|
-
const
|
|
77
|
-
String ( cursor ),
|
|
78
|
-
'MATCH', matchPattern.startsWith ( config?.redis?.prefix ) ? matchPattern : config?.redis?.prefix + matchPattern,
|
|
79
|
-
'COUNT', String ( count ),
|
|
80
|
-
];
|
|
153
|
+
const fullMatchPattern = matchPattern.startsWith ( config?.redis?.prefix ) ? matchPattern : config?.redis?.prefix + matchPattern;
|
|
81
154
|
|
|
82
|
-
|
|
155
|
+
// Directly use the scan method provided by ioredis
|
|
156
|
+
const result = await client.scan ( cursor, 'MATCH', fullMatchPattern, 'COUNT', count );
|
|
157
|
+
|
|
158
|
+
return result;
|
|
83
159
|
}
|
|
84
160
|
catch ( error ) {
|
|
85
161
|
console.log ( 'REDIS LIB ERROR [scan]', error );
|
|
@@ -101,11 +177,10 @@ exports.get = async ( key ) => {
|
|
|
101
177
|
if ( typeof key === 'string' ) {
|
|
102
178
|
const client = await getClient ();
|
|
103
179
|
|
|
104
|
-
const
|
|
105
|
-
key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key,
|
|
106
|
-
];
|
|
180
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
107
181
|
|
|
108
|
-
|
|
182
|
+
// Use the get method directly
|
|
183
|
+
const data = await client.get ( fullKey );
|
|
109
184
|
|
|
110
185
|
try {
|
|
111
186
|
return JSON.parse ( data );
|
|
@@ -137,9 +212,10 @@ exports.multiGet = async ( keys ) => {
|
|
|
137
212
|
if ( Array.isArray ( keys ) ) {
|
|
138
213
|
const client = await getClient ();
|
|
139
214
|
|
|
140
|
-
const
|
|
215
|
+
const fullKeys = keys.map ( key => key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key );
|
|
141
216
|
|
|
142
|
-
|
|
217
|
+
// Use the mget method directly
|
|
218
|
+
const data = await client.mget ( ...fullKeys );
|
|
143
219
|
|
|
144
220
|
return data.map ( val => {
|
|
145
221
|
try {
|
|
@@ -176,15 +252,12 @@ exports.set = async ( key, value, ex, px ) => {
|
|
|
176
252
|
if ( typeof key === 'string' ) {
|
|
177
253
|
const client = await getClient ();
|
|
178
254
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
];
|
|
183
|
-
|
|
184
|
-
if ( ex ) commandArgs.push ( 'EX', String ( ex ) );
|
|
185
|
-
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;
|
|
186
258
|
|
|
187
|
-
|
|
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 ] : [] ) );
|
|
188
261
|
}
|
|
189
262
|
|
|
190
263
|
throw new Error ( `redis.set expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -209,11 +282,10 @@ exports.del = async ( key ) => {
|
|
|
209
282
|
if ( typeof key === 'string' ) {
|
|
210
283
|
const client = await getClient ();
|
|
211
284
|
|
|
212
|
-
const
|
|
213
|
-
key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key,
|
|
214
|
-
];
|
|
285
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
215
286
|
|
|
216
|
-
|
|
287
|
+
// Use the del method directly
|
|
288
|
+
return await client.del ( fullKey );
|
|
217
289
|
}
|
|
218
290
|
|
|
219
291
|
throw new Error ( `redis.del expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -224,11 +296,42 @@ exports.del = async ( key ) => {
|
|
|
224
296
|
}
|
|
225
297
|
};
|
|
226
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 );
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
227
330
|
/**
|
|
228
331
|
* Adds one or more members to a set.
|
|
229
332
|
* @param {string} key - The key of the set.
|
|
230
333
|
* @param {string|string[]} members - The member(s) to add to the set.
|
|
231
|
-
* @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.
|
|
232
335
|
*
|
|
233
336
|
* @description This method adds one or more members to the specified set in Redis.
|
|
234
337
|
* If the set does not exist, it will be created.
|
|
@@ -240,12 +343,11 @@ exports.setAdd = async ( key, members ) => {
|
|
|
240
343
|
if ( typeof key === 'string' ) {
|
|
241
344
|
const client = await getClient ();
|
|
242
345
|
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
...( Array.isArray ( members ) ? members : [ members ] ),
|
|
246
|
-
];
|
|
346
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
347
|
+
const membersArray = Array.isArray ( members ) ? members : [ members ];
|
|
247
348
|
|
|
248
|
-
|
|
349
|
+
// Use the sadd method directly
|
|
350
|
+
return await client.sadd ( fullKey, ...membersArray );
|
|
249
351
|
}
|
|
250
352
|
|
|
251
353
|
throw new Error ( `redis.setAdd expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -260,7 +362,7 @@ exports.setAdd = async ( key, members ) => {
|
|
|
260
362
|
* Removes one or more members from a set.
|
|
261
363
|
* @param {string} key - The key of the set.
|
|
262
364
|
* @param {string|string[]} members - The member(s) to remove from the set.
|
|
263
|
-
* @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.
|
|
264
366
|
*
|
|
265
367
|
* @description This method removes one or more members from the specified set in Redis.
|
|
266
368
|
* If the set does not exist or if any member does not exist in the set, it will be ignored.
|
|
@@ -271,12 +373,11 @@ exports.setRemove = async ( key, members ) => {
|
|
|
271
373
|
if ( typeof key === 'string' ) {
|
|
272
374
|
const client = await getClient ();
|
|
273
375
|
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
...( Array.isArray ( members ) ? members : [ members ] ),
|
|
277
|
-
];
|
|
376
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
377
|
+
const membersArray = Array.isArray ( members ) ? members : [ members ];
|
|
278
378
|
|
|
279
|
-
|
|
379
|
+
// Use the srem method directly
|
|
380
|
+
return await client.srem ( fullKey, ...membersArray );
|
|
280
381
|
}
|
|
281
382
|
|
|
282
383
|
throw new Error ( `redis.setRemove expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -290,7 +391,7 @@ exports.setRemove = async ( key, members ) => {
|
|
|
290
391
|
/**
|
|
291
392
|
* Retrieves all members of a set.
|
|
292
393
|
* @param {string} key - The key of the set.
|
|
293
|
-
* @returns {Promise} - A promise that resolves with
|
|
394
|
+
* @returns {Promise<string[]>} - A promise that resolves with an array of members of the set.
|
|
294
395
|
*
|
|
295
396
|
* @description This method retrieves all members of the specified set in Redis.
|
|
296
397
|
* If the set does not exist, it will return an empty array.
|
|
@@ -300,11 +401,10 @@ exports.setMembers = async ( key ) => {
|
|
|
300
401
|
if ( typeof key === 'string' ) {
|
|
301
402
|
const client = await getClient ();
|
|
302
403
|
|
|
303
|
-
const
|
|
304
|
-
key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key,
|
|
305
|
-
];
|
|
404
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
306
405
|
|
|
307
|
-
|
|
406
|
+
// Use the smembers method directly
|
|
407
|
+
return await client.smembers ( fullKey );
|
|
308
408
|
}
|
|
309
409
|
|
|
310
410
|
throw new Error ( `redis.setMembers expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -318,7 +418,7 @@ exports.setMembers = async ( key ) => {
|
|
|
318
418
|
/**
|
|
319
419
|
* Removes and returns a random member from a set.
|
|
320
420
|
* @param {string} key - The key of the set.
|
|
321
|
-
* @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.
|
|
322
422
|
*
|
|
323
423
|
* @description
|
|
324
424
|
* This function removes and returns a random member from a set identified by the provided key.
|
|
@@ -330,21 +430,20 @@ exports.setPop = async ( key ) => {
|
|
|
330
430
|
try {
|
|
331
431
|
if ( typeof key === 'string' ) {
|
|
332
432
|
const client = await getClient ();
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
+
|
|
340
439
|
// If the member is null or an empty string, return null
|
|
341
440
|
if ( member === null || member === '' ) {
|
|
342
441
|
return null;
|
|
343
442
|
}
|
|
344
|
-
|
|
443
|
+
|
|
345
444
|
return member;
|
|
346
445
|
}
|
|
347
|
-
|
|
446
|
+
|
|
348
447
|
throw new Error ( `redis.setPop expects a string key, instead the type provided was: ${typeof key}` );
|
|
349
448
|
}
|
|
350
449
|
catch ( error ) {
|
|
@@ -357,7 +456,7 @@ exports.setPop = async ( key ) => {
|
|
|
357
456
|
* Prepends multiple values to the head of a list.
|
|
358
457
|
* @param {string} key - The key of the list.
|
|
359
458
|
* @param {string|string[]} values - The values to prepend to the list.
|
|
360
|
-
* @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.
|
|
361
460
|
*
|
|
362
461
|
* @description This method prepends one or more values to the head of the specified list in Redis.
|
|
363
462
|
* If the list does not exist, it will be created.
|
|
@@ -369,21 +468,11 @@ exports.listUnshift = async ( key, values ) => {
|
|
|
369
468
|
if ( typeof key === 'string' ) {
|
|
370
469
|
const client = await getClient ();
|
|
371
470
|
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
];
|
|
471
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
472
|
+
const valuesArray = Array.isArray ( values ) ? values : [ values ];
|
|
375
473
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
}
|
|
379
|
-
else if ( Array.isArray ( values ) ) {
|
|
380
|
-
commandArgs.push ( ...values );
|
|
381
|
-
}
|
|
382
|
-
else {
|
|
383
|
-
throw new Error ( `redis.listUnshift expects a string or an array of strings as the values, instead the type provided was: ${typeof values}` );
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
return await client.sendCommand ( [ 'LPUSH', ...commandArgs ] );
|
|
474
|
+
// Use the lpush method directly
|
|
475
|
+
return await client.lpush ( fullKey, ...valuesArray );
|
|
387
476
|
}
|
|
388
477
|
|
|
389
478
|
throw new Error ( `redis.listUnshift expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -398,7 +487,7 @@ exports.listUnshift = async ( key, values ) => {
|
|
|
398
487
|
* Pushes values to the tail of a list.
|
|
399
488
|
* @param {string} key - The key of the list.
|
|
400
489
|
* @param {string|string[]} values - The value(s) to push to the list.
|
|
401
|
-
* @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.
|
|
402
491
|
*
|
|
403
492
|
* @description This method pushes one or more values to the tail of the specified list in Redis.
|
|
404
493
|
* If the list does not exist, it will be created.
|
|
@@ -410,21 +499,11 @@ exports.listPush = async ( key, values ) => {
|
|
|
410
499
|
if ( typeof key === 'string' ) {
|
|
411
500
|
const client = await getClient ();
|
|
412
501
|
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
];
|
|
416
|
-
|
|
417
|
-
if ( typeof values === 'string' ) {
|
|
418
|
-
commandArgs.push ( values );
|
|
419
|
-
}
|
|
420
|
-
else if ( Array.isArray ( values ) ) {
|
|
421
|
-
commandArgs.push ( ...values );
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
throw new Error ( `redis.listPush expects a string or an array of strings as the values, instead the type provided was: ${typeof values}` );
|
|
425
|
-
}
|
|
502
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
503
|
+
const valuesArray = Array.isArray ( values ) ? values : [ values ];
|
|
426
504
|
|
|
427
|
-
|
|
505
|
+
// Use the rpush method directly
|
|
506
|
+
return await client.rpush ( fullKey, ...valuesArray );
|
|
428
507
|
}
|
|
429
508
|
|
|
430
509
|
throw new Error ( `redis.listPush expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -438,8 +517,8 @@ exports.listPush = async ( key, values ) => {
|
|
|
438
517
|
/**
|
|
439
518
|
* Removes and returns the first element of a list.
|
|
440
519
|
* @param {string} key - The key of the list.
|
|
441
|
-
* @param {number} count - The number of items to remove (default:
|
|
442
|
-
* @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).
|
|
443
522
|
*
|
|
444
523
|
* @description This method removes and returns the first element(s) from the specified list in Redis.
|
|
445
524
|
* If the list is empty or does not exist, it will return null.
|
|
@@ -451,12 +530,10 @@ exports.listPop = async ( key, count = 1 ) => {
|
|
|
451
530
|
if ( typeof key === 'string' ) {
|
|
452
531
|
const client = await getClient ();
|
|
453
532
|
|
|
454
|
-
const
|
|
455
|
-
key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key,
|
|
456
|
-
String ( count ),
|
|
457
|
-
];
|
|
533
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
458
534
|
|
|
459
|
-
|
|
535
|
+
// Use the lpop method directly with the count parameter
|
|
536
|
+
return await client.lpop ( fullKey, count );
|
|
460
537
|
}
|
|
461
538
|
|
|
462
539
|
throw new Error ( `redis.listPop expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -467,12 +544,37 @@ exports.listPop = async ( key, count = 1 ) => {
|
|
|
467
544
|
}
|
|
468
545
|
};
|
|
469
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 );
|
|
568
|
+
throw error;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
|
|
470
572
|
/**
|
|
471
573
|
* Retrieves a range of elements from a list.
|
|
472
574
|
* @param {string} key - The key of the list.
|
|
473
575
|
* @param {number} start - The starting index (default: 0).
|
|
474
576
|
* @param {number} end - The ending index (default: -1).
|
|
475
|
-
* @returns {Promise} - A promise that resolves with
|
|
577
|
+
* @returns {Promise<string[]>} - A promise that resolves with an array of elements from the specified range.
|
|
476
578
|
*
|
|
477
579
|
* @description This method retrieves a range of elements from the specified list in Redis.
|
|
478
580
|
* The range is specified by the start and end indices.
|
|
@@ -484,13 +586,10 @@ exports.listRange = async ( key, start = 0, end = -1 ) => {
|
|
|
484
586
|
if ( typeof key === 'string' ) {
|
|
485
587
|
const client = await getClient ();
|
|
486
588
|
|
|
487
|
-
const
|
|
488
|
-
key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key,
|
|
489
|
-
String ( start ),
|
|
490
|
-
String ( end ),
|
|
491
|
-
];
|
|
589
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
492
590
|
|
|
493
|
-
|
|
591
|
+
// Use the lrange method directly
|
|
592
|
+
return await client.lrange ( fullKey, start, end );
|
|
494
593
|
}
|
|
495
594
|
|
|
496
595
|
throw new Error ( `redis.listRange expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -504,7 +603,7 @@ exports.listRange = async ( key, start = 0, end = -1 ) => {
|
|
|
504
603
|
/**
|
|
505
604
|
* Retrieves the expiration time of a key in seconds.
|
|
506
605
|
* @param {string} key - The key to get the expiration time of.
|
|
507
|
-
* @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.
|
|
508
607
|
*
|
|
509
608
|
* @description This method retrieves the expiration time (in seconds) of the specified key in Redis.
|
|
510
609
|
* If the key does not exist or does not have an expiration set, it will return -1.
|
|
@@ -516,11 +615,10 @@ exports.getExpiryInSeconds = async ( key ) => {
|
|
|
516
615
|
if ( typeof key === 'string' ) {
|
|
517
616
|
const client = await getClient ();
|
|
518
617
|
|
|
519
|
-
const
|
|
520
|
-
key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key,
|
|
521
|
-
];
|
|
618
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
522
619
|
|
|
523
|
-
|
|
620
|
+
// Use the ttl method directly
|
|
621
|
+
return await client.ttl ( fullKey );
|
|
524
622
|
}
|
|
525
623
|
|
|
526
624
|
throw new Error ( `redis.getExpiryInSeconds expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -535,7 +633,7 @@ exports.getExpiryInSeconds = async ( key ) => {
|
|
|
535
633
|
* Sets the expiration time for a key in seconds.
|
|
536
634
|
* @param {string} key - The key to set the expiration time for.
|
|
537
635
|
* @param {number} seconds - The expiration time in seconds (default: 0).
|
|
538
|
-
* @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.
|
|
539
637
|
*
|
|
540
638
|
* @description This method sets the expiration time (in seconds) for the specified key in Redis.
|
|
541
639
|
* If the key does not exist, it will return 0 indicating no expiration was set.
|
|
@@ -546,12 +644,10 @@ exports.setExpiry = async ( key, seconds = 0 ) => {
|
|
|
546
644
|
if ( typeof key === 'string' ) {
|
|
547
645
|
const client = await getClient ();
|
|
548
646
|
|
|
549
|
-
const
|
|
550
|
-
key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key,
|
|
551
|
-
String ( seconds ),
|
|
552
|
-
];
|
|
647
|
+
const fullKey = key.startsWith ( config?.redis?.prefix ) ? key : config?.redis?.prefix + key;
|
|
553
648
|
|
|
554
|
-
|
|
649
|
+
// Use the expire method directly
|
|
650
|
+
return await client.expire ( fullKey, seconds );
|
|
555
651
|
}
|
|
556
652
|
|
|
557
653
|
throw new Error ( `redis.setExpiry expects a string key, instead the type provided was: ${typeof key}` );
|
|
@@ -562,9 +658,86 @@ exports.setExpiry = async ( key, seconds = 0 ) => {
|
|
|
562
658
|
}
|
|
563
659
|
};
|
|
564
660
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
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` );
|
|
673
|
+
|
|
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` );
|
|
568
697
|
|
|
569
|
-
|
|
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 () ) );
|
|
570
743
|
};
|