node-red-contrib-redis-variable 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +769 -0
- package/examples/example.json +427 -0
- package/package.json +46 -0
- package/redis-variable-config.html +731 -0
- package/redis-variable-config.js +363 -0
- package/redis-variable.html +284 -0
- package/redis-variable.js +621 -0
package/README.md
ADDED
|
@@ -0,0 +1,769 @@
|
|
|
1
|
+
# node-red-contrib-redis-variable
|
|
2
|
+
|
|
3
|
+
A comprehensive Node-RED node for Redis operations with flexible connection management and modern features.
|
|
4
|
+
|
|
5
|
+
**Developed by Andrii Lototskyi**
|
|
6
|
+
|
|
7
|
+
## 🚀 Features
|
|
8
|
+
|
|
9
|
+
### 🔧 **Flexible Connection Management**
|
|
10
|
+
- **Multiple Input Types**: Host, port, database, username, password support string values, flow/global context, and environment variables
|
|
11
|
+
- **Secure Credentials**: String values stored encrypted in Node-RED credentials
|
|
12
|
+
- **Runtime Resolution**: Context and environment variables resolved at runtime
|
|
13
|
+
- **SSL/TLS Support**: Full SSL/TLS encryption with client certificates and custom CAs
|
|
14
|
+
- **Advanced Configuration**: JSON-based advanced options for Redis client
|
|
15
|
+
|
|
16
|
+
### 📊 **Comprehensive Redis Operations**
|
|
17
|
+
|
|
18
|
+
#### **Universal Payload Interface**
|
|
19
|
+
- **Flexible Input**: All operations use `msg.payload` for parameters
|
|
20
|
+
- **Simple Format**: Single keys can be passed as strings
|
|
21
|
+
- **Object Format**: Complex operations use structured objects
|
|
22
|
+
- **Consistent Returns**: Standardized response format across all operations
|
|
23
|
+
|
|
24
|
+
#### **Basic Operations**
|
|
25
|
+
- **GET** - Retrieve value by key
|
|
26
|
+
- **SET** - Store value with optional TTL
|
|
27
|
+
- **DEL** - Delete single or multiple keys
|
|
28
|
+
- **EXISTS** - Check if single or multiple keys exist
|
|
29
|
+
|
|
30
|
+
#### **TTL Operations**
|
|
31
|
+
- **TTL** - Get remaining time to live in seconds
|
|
32
|
+
- **EXPIRE** - Set expiration time for existing key
|
|
33
|
+
- **PERSIST** - Remove expiration from key
|
|
34
|
+
|
|
35
|
+
#### **Counter Operations**
|
|
36
|
+
- **INCR** - Increment value by 1
|
|
37
|
+
- **DECR** - Decrement value by 1
|
|
38
|
+
- **INCRBY** - Increment value by N
|
|
39
|
+
- **DECRBY** - Decrement value by N
|
|
40
|
+
|
|
41
|
+
#### **List Operations**
|
|
42
|
+
- **LPUSH** - Add element to beginning of list
|
|
43
|
+
- **RPUSH** - Add element to end of list
|
|
44
|
+
- **LPOP** - Remove and return first element
|
|
45
|
+
- **RPOP** - Remove and return last element
|
|
46
|
+
- **LLEN** - Get list length
|
|
47
|
+
- **LRANGE** - Get range of elements
|
|
48
|
+
|
|
49
|
+
#### **Hash Operations**
|
|
50
|
+
- **HSET** - Set hash field value (single or multiple fields)
|
|
51
|
+
- **HGET** - Get hash field value
|
|
52
|
+
- **HGETALL** - Get all hash fields and values
|
|
53
|
+
- **HDEL** - Delete hash field(s)
|
|
54
|
+
|
|
55
|
+
#### **Pub/Sub Operations**
|
|
56
|
+
- **PUBLISH** - Publish message to channel
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install node-red-contrib-redis-variable
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Or install directly through the Node-RED palette manager.
|
|
65
|
+
|
|
66
|
+
## Configuration
|
|
67
|
+
|
|
68
|
+
### Redis Configuration Node
|
|
69
|
+
|
|
70
|
+
The Redis configuration node supports flexible connection parameters:
|
|
71
|
+
|
|
72
|
+
#### Connection Settings
|
|
73
|
+
- **Host**: Redis server hostname or IP address
|
|
74
|
+
- **Port**: Redis server port (default: 6379)
|
|
75
|
+
- **Database**: Redis database number (default: 0)
|
|
76
|
+
- **Cluster Mode**: Enable for Redis Cluster deployments
|
|
77
|
+
|
|
78
|
+
#### Authentication
|
|
79
|
+
- **Username**: Redis username (Redis 6.0+ ACL support)
|
|
80
|
+
- **Password**: Redis password for authentication
|
|
81
|
+
|
|
82
|
+
#### Credential Sources
|
|
83
|
+
All connection parameters support multiple input types:
|
|
84
|
+
- **String**: Direct value stored securely in Node-RED credentials
|
|
85
|
+
- **Flow Context**: Retrieved from flow context variables
|
|
86
|
+
- **Global Context**: Retrieved from global context variables
|
|
87
|
+
- **Environment Variable**: Retrieved from environment variables
|
|
88
|
+
|
|
89
|
+
#### Advanced Options
|
|
90
|
+
JSON object with additional ioredis connection options:
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"connectTimeout": 10000,
|
|
94
|
+
"lazyConnect": true,
|
|
95
|
+
"keepAlive": 30000,
|
|
96
|
+
"family": 4,
|
|
97
|
+
"retryDelayOnFailover": 100
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### SSL/TLS Configuration
|
|
102
|
+
The module provides comprehensive SSL/TLS support for secure Redis connections:
|
|
103
|
+
|
|
104
|
+
##### SSL Settings
|
|
105
|
+
- **Enable SSL/TLS**: Enable secure connection to Redis server
|
|
106
|
+
- **Verify Certificate**: Validate server certificates (recommended for production)
|
|
107
|
+
- **Client Certificate**: Client certificate for mutual TLS authentication
|
|
108
|
+
- **Private Key**: Private key corresponding to client certificate
|
|
109
|
+
- **CA Certificate**: Certificate Authority certificate for custom CAs
|
|
110
|
+
|
|
111
|
+
##### SSL Examples
|
|
112
|
+
|
|
113
|
+
**Basic SSL (server verification only):**
|
|
114
|
+
```
|
|
115
|
+
Enable SSL/TLS: ✓
|
|
116
|
+
Verify Certificate: ✓
|
|
117
|
+
Client Certificate: (empty)
|
|
118
|
+
Private Key: (empty)
|
|
119
|
+
CA Certificate: (empty)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Mutual TLS (client + server authentication):**
|
|
123
|
+
```
|
|
124
|
+
Enable SSL/TLS: ✓
|
|
125
|
+
Verify Certificate: ✓
|
|
126
|
+
Client Certificate: Your client certificate
|
|
127
|
+
Private Key: Your private key
|
|
128
|
+
CA Certificate: Custom CA if needed
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Self-signed certificates:**
|
|
132
|
+
```
|
|
133
|
+
Enable SSL/TLS: ✓
|
|
134
|
+
Verify Certificate: ✗ (disable for self-signed)
|
|
135
|
+
CA Certificate: Your self-signed CA
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Environment-based SSL configuration:**
|
|
139
|
+
```
|
|
140
|
+
Enable SSL/TLS: ✓
|
|
141
|
+
Client Certificate Type: Environment Variable → TLS_CLIENT_CERT
|
|
142
|
+
Private Key Type: Environment Variable → TLS_PRIVATE_KEY
|
|
143
|
+
CA Certificate Type: Environment Variable → TLS_CA_CERT
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Example Configurations
|
|
147
|
+
|
|
148
|
+
#### Environment-based Configuration
|
|
149
|
+
```
|
|
150
|
+
Host: Environment Variable → REDIS_HOST
|
|
151
|
+
Port: Environment Variable → REDIS_PORT
|
|
152
|
+
Password: Environment Variable → REDIS_PASSWORD
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
#### Context-based Configuration
|
|
156
|
+
```
|
|
157
|
+
Host: Global Context → redis_config.host
|
|
158
|
+
Port: Global Context → redis_config.port
|
|
159
|
+
Password: Flow Context → redis_password
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Operations
|
|
163
|
+
|
|
164
|
+
**Universal Payload Interface**: All Redis operations use a unified `msg.payload` interface. Parameters can be passed as simple strings (for single keys) or as objects with specific properties. This provides flexibility while maintaining simplicity.
|
|
165
|
+
|
|
166
|
+
### Basic Operations
|
|
167
|
+
|
|
168
|
+
#### GET - Retrieve Value
|
|
169
|
+
```javascript
|
|
170
|
+
// Simple key format
|
|
171
|
+
msg.payload = "user:123";
|
|
172
|
+
// Returns: { payload: "stored_value" }
|
|
173
|
+
|
|
174
|
+
// Object format
|
|
175
|
+
msg.payload = {
|
|
176
|
+
key: "user:123"
|
|
177
|
+
};
|
|
178
|
+
// Returns: { payload: "stored_value" }
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### SET - Store Value
|
|
182
|
+
```javascript
|
|
183
|
+
// Simple SET
|
|
184
|
+
msg.payload = {
|
|
185
|
+
key: "user:123",
|
|
186
|
+
value: "John Doe"
|
|
187
|
+
};
|
|
188
|
+
// Returns: { payload: { success: true, result: "OK", ttl: null } }
|
|
189
|
+
|
|
190
|
+
// SET with TTL
|
|
191
|
+
msg.payload = {
|
|
192
|
+
key: "session:abc123",
|
|
193
|
+
value: { userId: 42, role: "admin" },
|
|
194
|
+
ttl: 3600
|
|
195
|
+
};
|
|
196
|
+
// Returns: { payload: { success: true, result: "OK", ttl: 3600 } }
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### DEL - Delete Key
|
|
200
|
+
```javascript
|
|
201
|
+
// Delete single key
|
|
202
|
+
msg.payload = {
|
|
203
|
+
key: "mykey"
|
|
204
|
+
};
|
|
205
|
+
// Or simple format
|
|
206
|
+
msg.payload = "mykey";
|
|
207
|
+
// Returns: { payload: { success: true, deleted: 1, keys: ["mykey"] } }
|
|
208
|
+
|
|
209
|
+
// Delete multiple keys
|
|
210
|
+
msg.payload = {
|
|
211
|
+
keys: ["key1", "key2", "key3"]
|
|
212
|
+
};
|
|
213
|
+
// Returns: { payload: { success: true, deleted: 3, keys: ["key1", "key2", "key3"] } }
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### EXISTS - Check Key Existence
|
|
217
|
+
```javascript
|
|
218
|
+
// Check single key
|
|
219
|
+
msg.payload = "mykey";
|
|
220
|
+
// Or object format
|
|
221
|
+
msg.payload = {
|
|
222
|
+
key: "mykey"
|
|
223
|
+
};
|
|
224
|
+
// Returns: { payload: { exists: true, count: 1, keys: ["mykey"] } }
|
|
225
|
+
|
|
226
|
+
// Check multiple keys
|
|
227
|
+
msg.payload = {
|
|
228
|
+
keys: ["key1", "key2", "key3"]
|
|
229
|
+
};
|
|
230
|
+
// Returns: { payload: { exists: true, count: 2, keys: ["key1", "key2", "key3"] } }
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### TTL - Get Time To Live
|
|
234
|
+
```javascript
|
|
235
|
+
msg.payload = "mykey";
|
|
236
|
+
// Returns: { payload: { key: "mykey", ttl: 3600, status: "expires in 3600 seconds" } }
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### EXPIRE - Set Key Expiration
|
|
240
|
+
```javascript
|
|
241
|
+
msg.payload = {
|
|
242
|
+
key: "mykey",
|
|
243
|
+
ttl: 3600
|
|
244
|
+
};
|
|
245
|
+
// Returns: { payload: { success: true, key: "mykey", ttl: 3600, message: "Expiration set" } }
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### PERSIST - Remove Expiration
|
|
249
|
+
```javascript
|
|
250
|
+
msg.payload = "mykey";
|
|
251
|
+
// Returns: { payload: { success: true, key: "mykey", message: "Expiration removed" } }
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
#### INCR/DECR - Increment/Decrement
|
|
255
|
+
```javascript
|
|
256
|
+
// Simple increment
|
|
257
|
+
msg.payload = "counter";
|
|
258
|
+
// Returns: { payload: { key: "counter", value: 1 } }
|
|
259
|
+
|
|
260
|
+
// Increment by amount
|
|
261
|
+
msg.payload = {
|
|
262
|
+
key: "score",
|
|
263
|
+
amount: 10
|
|
264
|
+
};
|
|
265
|
+
// Returns: { payload: { key: "score", value: 110, increment: 10 } }
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### List Operations
|
|
269
|
+
|
|
270
|
+
#### LPUSH/RPUSH - Add to List
|
|
271
|
+
```javascript
|
|
272
|
+
msg.payload = {
|
|
273
|
+
key: "mylist",
|
|
274
|
+
value: "item1"
|
|
275
|
+
};
|
|
276
|
+
// Returns: { payload: { success: true, key: "mylist", length: 1, operation: "lpush" } }
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### LPOP/RPOP - Remove from List
|
|
280
|
+
```javascript
|
|
281
|
+
msg.payload = "mylist";
|
|
282
|
+
// Returns: { payload: "item1" }
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### LLEN - Get List Length
|
|
286
|
+
```javascript
|
|
287
|
+
msg.payload = "mylist";
|
|
288
|
+
// Returns: { payload: { key: "mylist", length: 5 } }
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### LRANGE - Get List Range
|
|
292
|
+
```javascript
|
|
293
|
+
msg.payload = {
|
|
294
|
+
key: "mylist",
|
|
295
|
+
start: 0,
|
|
296
|
+
stop: -1
|
|
297
|
+
};
|
|
298
|
+
// Returns: { payload: { key: "mylist", range: {start: 0, stop: -1}, values: ["item1", "item2", "item3"], count: 3 } }
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
#### BLPOP/BRPOP - Blocking Pop
|
|
302
|
+
Configure timeout in node settings. These operations run continuously and emit messages when items are available.
|
|
303
|
+
|
|
304
|
+
### Hash Operations
|
|
305
|
+
|
|
306
|
+
#### HSET - Set Hash Field
|
|
307
|
+
```javascript
|
|
308
|
+
// Single field
|
|
309
|
+
msg.payload = {
|
|
310
|
+
key: "myhash",
|
|
311
|
+
field: "name",
|
|
312
|
+
value: "John"
|
|
313
|
+
};
|
|
314
|
+
// Returns: { payload: { success: true, key: "myhash", field: "name", created: true } }
|
|
315
|
+
|
|
316
|
+
// Multiple fields
|
|
317
|
+
msg.payload = {
|
|
318
|
+
key: "myhash",
|
|
319
|
+
fields: {
|
|
320
|
+
name: "John",
|
|
321
|
+
age: 30,
|
|
322
|
+
city: "New York"
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
// Returns: { payload: { success: true, key: "myhash", fields: ["name", "age", "city"], created: 3 } }
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
#### HGET - Get Hash Field
|
|
329
|
+
```javascript
|
|
330
|
+
msg.payload = {
|
|
331
|
+
key: "myhash",
|
|
332
|
+
field: "name"
|
|
333
|
+
};
|
|
334
|
+
// Returns: { payload: "John" }
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
#### HGETALL - Get All Hash Fields
|
|
338
|
+
```javascript
|
|
339
|
+
msg.payload = "myhash";
|
|
340
|
+
// Returns: { payload: { name: "John", age: "30", city: "New York" } }
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
#### HDEL - Delete Hash Field
|
|
344
|
+
```javascript
|
|
345
|
+
// Delete single field
|
|
346
|
+
msg.payload = {
|
|
347
|
+
key: "myhash",
|
|
348
|
+
field: "age"
|
|
349
|
+
};
|
|
350
|
+
// Returns: { payload: { success: true, key: "myhash", deleted: 1, fields: ["age"] } }
|
|
351
|
+
|
|
352
|
+
// Delete multiple fields
|
|
353
|
+
msg.payload = {
|
|
354
|
+
key: "myhash",
|
|
355
|
+
fields: ["age", "city"]
|
|
356
|
+
};
|
|
357
|
+
// Returns: { payload: { success: true, key: "myhash", deleted: 2, fields: ["age", "city"] } }
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Pub/Sub Operations
|
|
361
|
+
|
|
362
|
+
#### PUBLISH - Publish Message
|
|
363
|
+
```javascript
|
|
364
|
+
msg.payload = {
|
|
365
|
+
channel: "mychannel",
|
|
366
|
+
message: "Hello World"
|
|
367
|
+
};
|
|
368
|
+
// Returns: { payload: { success: true, channel: "mychannel", subscribers: 2, message: "Hello World" } }
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
#### SUBSCRIBE - Subscribe to Channel
|
|
372
|
+
Configure channel in node settings. Messages are automatically emitted:
|
|
373
|
+
```javascript
|
|
374
|
+
// Received message format:
|
|
375
|
+
{
|
|
376
|
+
topic: "mychannel",
|
|
377
|
+
payload: "Hello World"
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
#### PSUBSCRIBE - Pattern Subscribe
|
|
382
|
+
Configure pattern in node settings (e.g., "news.*"):
|
|
383
|
+
```javascript
|
|
384
|
+
// Received message format:
|
|
385
|
+
{
|
|
386
|
+
pattern: "news.*",
|
|
387
|
+
topic: "news.sports",
|
|
388
|
+
payload: "Sports update"
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Advanced Operations
|
|
393
|
+
|
|
394
|
+
#### Lua Script Execution
|
|
395
|
+
```javascript
|
|
396
|
+
// Configure Lua script in node editor:
|
|
397
|
+
// return redis.call('GET', KEYS[1])
|
|
398
|
+
|
|
399
|
+
msg.payload = ["mykey"]; // Array of keys and arguments
|
|
400
|
+
// Returns: { payload: "script_result" }
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
#### Redis Instance in Context
|
|
404
|
+
Stores Redis client in flow or global context for direct access:
|
|
405
|
+
```javascript
|
|
406
|
+
// Access stored instance
|
|
407
|
+
const redis = flow.get("redis_client");
|
|
408
|
+
const result = await redis.get("mykey");
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## 🔄 Automatic JSON Handling
|
|
412
|
+
|
|
413
|
+
The module automatically detects and handles JSON data without any configuration:
|
|
414
|
+
|
|
415
|
+
### 🤖 Smart Detection
|
|
416
|
+
- **Objects**: JavaScript objects are automatically serialized to JSON strings when storing
|
|
417
|
+
- **JSON Strings**: Valid JSON strings are automatically parsed back to objects when retrieving
|
|
418
|
+
- **Simple Values**: Strings, numbers, and other simple types are handled as-is
|
|
419
|
+
- **Arrays**: Each item in Redis lists is automatically parsed if it's valid JSON
|
|
420
|
+
|
|
421
|
+
### 📝 Examples
|
|
422
|
+
|
|
423
|
+
#### Storing Objects
|
|
424
|
+
```javascript
|
|
425
|
+
msg.payload = {
|
|
426
|
+
key: "user:123",
|
|
427
|
+
value: {
|
|
428
|
+
name: "John Doe",
|
|
429
|
+
age: 30,
|
|
430
|
+
preferences: {
|
|
431
|
+
theme: "dark",
|
|
432
|
+
language: "en"
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
// Automatically stored as: '{"name":"John Doe","age":30,"preferences":{"theme":"dark","language":"en"}}'
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### Retrieving Objects
|
|
440
|
+
```javascript
|
|
441
|
+
msg.payload = "user:123";
|
|
442
|
+
// Returns: {
|
|
443
|
+
// "name": "John Doe",
|
|
444
|
+
// "age": 30,
|
|
445
|
+
// "preferences": {
|
|
446
|
+
// "theme": "dark",
|
|
447
|
+
// "language": "en"
|
|
448
|
+
// }
|
|
449
|
+
// }
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
#### Mixed Data Types
|
|
453
|
+
```javascript
|
|
454
|
+
// Store simple string
|
|
455
|
+
msg.payload = {
|
|
456
|
+
key: "message",
|
|
457
|
+
value: "Hello World"
|
|
458
|
+
};
|
|
459
|
+
// Returns: "Hello World"
|
|
460
|
+
|
|
461
|
+
// Store number
|
|
462
|
+
msg.payload = {
|
|
463
|
+
key: "count",
|
|
464
|
+
value: 42
|
|
465
|
+
};
|
|
466
|
+
// Returns: "42"
|
|
467
|
+
|
|
468
|
+
// Store object
|
|
469
|
+
msg.payload = {
|
|
470
|
+
key: "config",
|
|
471
|
+
value: {
|
|
472
|
+
debug: true,
|
|
473
|
+
timeout: 5000
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
// Returns: {debug: true, timeout: 5000}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Connection Management
|
|
480
|
+
|
|
481
|
+
### Connection Pooling
|
|
482
|
+
- Connections are automatically pooled and reused across nodes
|
|
483
|
+
- Each configuration creates a single connection pool
|
|
484
|
+
- Connections are automatically cleaned up when nodes are removed
|
|
485
|
+
|
|
486
|
+
### Blocking Operations
|
|
487
|
+
For blocking operations (BLPOP, BRPOP, Lua scripts), enable "Force new connection" to prevent blocking other operations.
|
|
488
|
+
|
|
489
|
+
### Error Handling
|
|
490
|
+
All operations include comprehensive error handling:
|
|
491
|
+
```javascript
|
|
492
|
+
// Error response format:
|
|
493
|
+
{
|
|
494
|
+
payload: {
|
|
495
|
+
error: "Connection failed: ECONNREFUSED"
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
## Security Best Practices
|
|
501
|
+
|
|
502
|
+
1. **Use Environment Variables**: Store sensitive credentials in environment variables
|
|
503
|
+
2. **Enable Redis AUTH**: Always use password authentication in production
|
|
504
|
+
3. **Use Redis ACLs**: Implement fine-grained access control (Redis 6.0+)
|
|
505
|
+
4. **Enable SSL/TLS**: Use encrypted connections for production environments
|
|
506
|
+
5. **Verify Certificates**: Always verify server certificates in production
|
|
507
|
+
6. **Secure Certificate Storage**: Store certificates and keys in environment variables or secure context
|
|
508
|
+
7. **Network Security**: Use TLS/SSL for connections over untrusted networks
|
|
509
|
+
8. **Principle of Least Privilege**: Grant minimal required permissions
|
|
510
|
+
|
|
511
|
+
## Examples
|
|
512
|
+
|
|
513
|
+
### Basic Key-Value Storage
|
|
514
|
+
```javascript
|
|
515
|
+
// Store user session
|
|
516
|
+
msg.payload = {
|
|
517
|
+
key: "session:abc123",
|
|
518
|
+
value: {
|
|
519
|
+
userId: 456,
|
|
520
|
+
loginTime: new Date().toISOString(),
|
|
521
|
+
permissions: ["read", "write"]
|
|
522
|
+
},
|
|
523
|
+
ttl: 3600 // 1 hour expiration
|
|
524
|
+
};
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Message Queue with Lists
|
|
528
|
+
```javascript
|
|
529
|
+
// Producer - Add task to queue
|
|
530
|
+
msg.payload = {
|
|
531
|
+
key: "task_queue",
|
|
532
|
+
value: {
|
|
533
|
+
id: "task_001",
|
|
534
|
+
type: "email",
|
|
535
|
+
data: { to: "user@example.com", subject: "Welcome" }
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
// Consumer (using BLPOP)
|
|
540
|
+
// Configure BLPOP operation in node settings
|
|
541
|
+
// Automatically receives tasks as they're added
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
### Caching with Expiration
|
|
545
|
+
```javascript
|
|
546
|
+
// Cache API response for 1 hour
|
|
547
|
+
msg.payload = {
|
|
548
|
+
key: "api_cache:users",
|
|
549
|
+
value: apiResponse,
|
|
550
|
+
ttl: 3600 // 1 hour
|
|
551
|
+
};
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Real-time Notifications
|
|
555
|
+
```javascript
|
|
556
|
+
// Publisher
|
|
557
|
+
msg.payload = {
|
|
558
|
+
channel: "notifications:user:123",
|
|
559
|
+
message: {
|
|
560
|
+
type: "message",
|
|
561
|
+
from: "user:456",
|
|
562
|
+
content: "Hello there!"
|
|
563
|
+
}
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
// Subscriber automatically receives notifications
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
## 📖 Usage Examples
|
|
570
|
+
|
|
571
|
+
### Basic Operations
|
|
572
|
+
|
|
573
|
+
#### GET Operation
|
|
574
|
+
```javascript
|
|
575
|
+
// Simple format
|
|
576
|
+
msg.payload = "user:123";
|
|
577
|
+
|
|
578
|
+
// Object format
|
|
579
|
+
msg.payload = {
|
|
580
|
+
key: "user:123"
|
|
581
|
+
};
|
|
582
|
+
// Returns: "John Doe" (or stored value)
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
#### SET Operation
|
|
586
|
+
```javascript
|
|
587
|
+
// Simple SET
|
|
588
|
+
msg.payload = {
|
|
589
|
+
key: "user:123",
|
|
590
|
+
value: "John Doe"
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
// SET with TTL (expires in 1 hour)
|
|
594
|
+
msg.payload = {
|
|
595
|
+
key: "session:abc123",
|
|
596
|
+
value: {userId: 42, role: "admin"},
|
|
597
|
+
ttl: 3600
|
|
598
|
+
};
|
|
599
|
+
// Returns: { success: true, result: "OK", ttl: 3600 }
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
#### DELETE Operations
|
|
603
|
+
```javascript
|
|
604
|
+
// Delete single key
|
|
605
|
+
msg.payload = {
|
|
606
|
+
key: "temp:data"
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
// Delete multiple keys
|
|
610
|
+
msg.payload = {
|
|
611
|
+
keys: ["cache:page1", "cache:page2", "temp:data"]
|
|
612
|
+
};
|
|
613
|
+
// Returns: { success: true, deleted: 3, keys: [...] }
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
### TTL Operations
|
|
617
|
+
|
|
618
|
+
#### Check TTL
|
|
619
|
+
```javascript
|
|
620
|
+
msg.payload = "session:abc123";
|
|
621
|
+
// Returns: { key: "session:abc123", ttl: 2847, status: "expires in 2847 seconds" }
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
#### Set Expiration
|
|
625
|
+
```javascript
|
|
626
|
+
msg.payload = {
|
|
627
|
+
key: "temp:data",
|
|
628
|
+
ttl: 1800
|
|
629
|
+
};
|
|
630
|
+
// Returns: { success: true, key: "temp:data", ttl: 1800, message: "Expiration set" }
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
#### Remove Expiration
|
|
634
|
+
```javascript
|
|
635
|
+
msg.payload = "permanent:key";
|
|
636
|
+
// Returns: { success: true, key: "permanent:key", message: "Expiration removed" }
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Counter Operations
|
|
640
|
+
|
|
641
|
+
#### Increment Counter
|
|
642
|
+
```javascript
|
|
643
|
+
// Simple increment
|
|
644
|
+
msg.payload = "page:views";
|
|
645
|
+
// Returns: { key: "page:views", value: 1547 }
|
|
646
|
+
|
|
647
|
+
// Increment by amount
|
|
648
|
+
msg.payload = {
|
|
649
|
+
key: "score:player1",
|
|
650
|
+
amount: 100
|
|
651
|
+
};
|
|
652
|
+
// Returns: { key: "score:player1", value: 2350, increment: 100 }
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### List Operations
|
|
656
|
+
|
|
657
|
+
#### Add to List
|
|
658
|
+
```javascript
|
|
659
|
+
msg.payload = {
|
|
660
|
+
key: "queue:tasks",
|
|
661
|
+
value: {
|
|
662
|
+
task: "process_order",
|
|
663
|
+
id: 12345
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
// Returns: { success: true, key: "queue:tasks", length: 8, operation: "lpush" }
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
#### Get List Range
|
|
670
|
+
```javascript
|
|
671
|
+
msg.payload = {
|
|
672
|
+
key: "queue:tasks",
|
|
673
|
+
start: 0,
|
|
674
|
+
stop: 4
|
|
675
|
+
};
|
|
676
|
+
// Returns: { key: "queue:tasks", range: {start: 0, stop: 4}, values: [...], count: 5 }
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
#### Pop from List
|
|
680
|
+
```javascript
|
|
681
|
+
msg.payload = "queue:tasks";
|
|
682
|
+
// Returns: {"task": "process_order", "id": 12345} (first item)
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
### Hash Operations
|
|
686
|
+
|
|
687
|
+
#### Set Hash Fields
|
|
688
|
+
```javascript
|
|
689
|
+
// Single field
|
|
690
|
+
msg.payload = {
|
|
691
|
+
key: "user:123",
|
|
692
|
+
field: "email",
|
|
693
|
+
value: "john.doe@example.com"
|
|
694
|
+
};
|
|
695
|
+
// Returns: { success: true, key: "user:123", field: "email", created: true }
|
|
696
|
+
|
|
697
|
+
// Multiple fields
|
|
698
|
+
msg.payload = {
|
|
699
|
+
key: "user:123",
|
|
700
|
+
fields: {
|
|
701
|
+
name: "John Doe",
|
|
702
|
+
age: 30,
|
|
703
|
+
city: "New York",
|
|
704
|
+
active: true
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
// Returns: { success: true, key: "user:123", fields: ["name", "age", "city", "active"], created: 4 }
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
#### Get Hash Data
|
|
711
|
+
```javascript
|
|
712
|
+
// Get single field
|
|
713
|
+
msg.payload = {
|
|
714
|
+
key: "user:123",
|
|
715
|
+
field: "email"
|
|
716
|
+
};
|
|
717
|
+
// Returns: "john.doe@example.com"
|
|
718
|
+
|
|
719
|
+
// Get all fields
|
|
720
|
+
msg.payload = "user:123";
|
|
721
|
+
// Returns: { name: "John Doe", age: "30", city: "New York", email: "john.doe@example.com", active: "true" }
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
### Pub/Sub Operations
|
|
725
|
+
|
|
726
|
+
#### Publish Message
|
|
727
|
+
```javascript
|
|
728
|
+
msg.payload = {
|
|
729
|
+
channel: "notifications",
|
|
730
|
+
message: {
|
|
731
|
+
type: "alert",
|
|
732
|
+
text: "System maintenance in 5 minutes",
|
|
733
|
+
timestamp: "2024-01-15T10:30:00Z"
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
// Returns: { success: true, channel: "notifications", subscribers: 3, message: "..." }
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
## Troubleshooting
|
|
740
|
+
|
|
741
|
+
### Common Issues
|
|
742
|
+
|
|
743
|
+
1. **Connection Refused**: Check Redis server is running and accessible
|
|
744
|
+
2. **Authentication Failed**: Verify username/password configuration
|
|
745
|
+
3. **Timeout Errors**: Increase connection timeout in advanced options
|
|
746
|
+
4. **Memory Issues**: Monitor Redis memory usage and configure appropriate limits
|
|
747
|
+
|
|
748
|
+
### Debug Mode
|
|
749
|
+
Enable Node-RED debug mode to see detailed connection and operation logs:
|
|
750
|
+
```bash
|
|
751
|
+
DEBUG=redis* node-red
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
## Contributing
|
|
755
|
+
|
|
756
|
+
Contributions are welcome! Please read the contributing guidelines and submit pull requests to the GitHub repository.
|
|
757
|
+
|
|
758
|
+
## License
|
|
759
|
+
|
|
760
|
+
MIT License - see LICENSE file for details.
|
|
761
|
+
|
|
762
|
+
## Changelog
|
|
763
|
+
|
|
764
|
+
### v1.0.0
|
|
765
|
+
- Initial release
|
|
766
|
+
- Complete Redis operations support
|
|
767
|
+
- Flexible connection management
|
|
768
|
+
- Modern ioredis integration
|
|
769
|
+
- Comprehensive documentation
|