redux-cluster 1.10.0 → 2.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 -21
- package/README.md +345 -471
- package/dist/cjs/core/backup.d.ts +10 -0
- package/dist/cjs/core/backup.d.ts.map +1 -0
- package/dist/cjs/core/backup.js +166 -0
- package/dist/cjs/core/redux-cluster.d.ts +47 -0
- package/dist/cjs/core/redux-cluster.d.ts.map +1 -0
- package/dist/cjs/core/redux-cluster.js +367 -0
- package/dist/cjs/index.d.ts +22 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +43 -0
- package/dist/cjs/network/client.d.ts +23 -0
- package/dist/cjs/network/client.d.ts.map +1 -0
- package/dist/cjs/network/client.js +251 -0
- package/dist/cjs/network/server.d.ts +39 -0
- package/dist/cjs/network/server.d.ts.map +1 -0
- package/dist/cjs/network/server.js +439 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types/index.d.ts +125 -0
- package/dist/cjs/types/index.d.ts.map +1 -0
- package/dist/cjs/types/index.js +20 -0
- package/dist/cjs/utils/crypto.d.ts +22 -0
- package/dist/cjs/utils/crypto.d.ts.map +1 -0
- package/dist/cjs/utils/crypto.js +404 -0
- package/dist/esm/core/backup.d.ts +10 -0
- package/dist/esm/core/backup.d.ts.map +1 -0
- package/dist/esm/core/backup.js +134 -0
- package/dist/esm/core/redux-cluster.d.ts +47 -0
- package/dist/esm/core/redux-cluster.d.ts.map +1 -0
- package/dist/esm/core/redux-cluster.js +376 -0
- package/dist/esm/index.d.ts +22 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +25 -0
- package/dist/esm/network/client.d.ts +23 -0
- package/dist/esm/network/client.d.ts.map +1 -0
- package/dist/esm/network/client.js +221 -0
- package/dist/esm/network/server.d.ts +39 -0
- package/dist/esm/network/server.d.ts.map +1 -0
- package/dist/esm/network/server.js +408 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/types/index.d.ts +125 -0
- package/dist/esm/types/index.d.ts.map +1 -0
- package/dist/esm/types/index.js +17 -0
- package/dist/esm/utils/crypto.d.ts +22 -0
- package/dist/esm/utils/crypto.d.ts.map +1 -0
- package/dist/esm/utils/crypto.js +351 -0
- package/package.json +115 -34
- package/index.js +0 -678
- package/test.auto.js +0 -94
- package/test.auto.proc1.js +0 -97
- package/test.auto.proc2.js +0 -85
- package/test.visual.client.highload.js +0 -102
- package/test.visual.client.js +0 -103
- package/test.visual.error.js +0 -45
- package/test.visual.js +0 -97
- package/test.visual.server.highload.js +0 -102
- package/test.visual.server.js +0 -103
package/README.md
CHANGED
|
@@ -1,471 +1,345 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
###
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
} else {
|
|
347
|
-
Test.dispatch({type:'TASK', payload: {version:'WorkerTest'+Cluster.worker.id}});
|
|
348
|
-
}
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
#### Cluster Scheme Server
|
|
352
|
-
|
|
353
|
-
```
|
|
354
|
-
var ReduxCluster = require('redux-cluster'),
|
|
355
|
-
Cluster = require('cluster'),
|
|
356
|
-
Lodash = require('lodash');
|
|
357
|
-
|
|
358
|
-
var Test = ReduxCluster.createStore(editProcessStorage);
|
|
359
|
-
|
|
360
|
-
if(Cluster.isMaster){
|
|
361
|
-
Test.createServer({path: "./mysock.sock", logins:{test1:'12345'}});
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
function editProcessStorage(state = {version:''}, action){
|
|
365
|
-
try {
|
|
366
|
-
switch (action.type){
|
|
367
|
-
case 'TASK':
|
|
368
|
-
var state_new = Lodash.clone(state);
|
|
369
|
-
state_new.version = action.payload.version;
|
|
370
|
-
return state_new;
|
|
371
|
-
break;
|
|
372
|
-
default:
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
375
|
-
} catch(e){
|
|
376
|
-
}
|
|
377
|
-
var state_new = Lodash.clone(state);
|
|
378
|
-
return state_new;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
Test.subscribe(function(){
|
|
382
|
-
if(Cluster.isMaster){
|
|
383
|
-
var name = 'm';
|
|
384
|
-
} else {
|
|
385
|
-
var name = Cluster.worker.id;
|
|
386
|
-
}
|
|
387
|
-
console.log(' S1 | ' + name + ' | ' + JSON.stringify(Test.getState()));
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
if(Cluster.isMaster){
|
|
391
|
-
for(var i=0; i < 1; i++){
|
|
392
|
-
setTimeout(function(){Cluster.fork();}, i*10000);
|
|
393
|
-
}
|
|
394
|
-
var i = 0;
|
|
395
|
-
setInterval(function(){
|
|
396
|
-
Test.dispatch({type:'TASK', payload: {version:'MasterTest'+i}});
|
|
397
|
-
i++;
|
|
398
|
-
}, 19000);
|
|
399
|
-
} else {
|
|
400
|
-
var i = 0;
|
|
401
|
-
setInterval(function(){
|
|
402
|
-
Test.dispatch({type:'TASK', payload: {version:'WorkerTest'+i}});
|
|
403
|
-
i++;
|
|
404
|
-
}, 31000+(Cluster.worker.id*3600), i);
|
|
405
|
-
}
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
#### Cluster Scheme Client
|
|
409
|
-
|
|
410
|
-
```
|
|
411
|
-
var ReduxCluster = require('redux-cluster'),
|
|
412
|
-
Cluster = require('cluster'),
|
|
413
|
-
Lodash = require('lodash');
|
|
414
|
-
|
|
415
|
-
var Test = ReduxCluster.createStore(editProcessStorage);
|
|
416
|
-
|
|
417
|
-
if(Cluster.isMaster){
|
|
418
|
-
Test.createClient({path: "./mysock.sock", login:"test1", password:'12345'});
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function editProcessStorage(state = {version:''}, action){
|
|
422
|
-
try {
|
|
423
|
-
switch (action.type){
|
|
424
|
-
case 'TASK':
|
|
425
|
-
var state_new = Lodash.clone(state);
|
|
426
|
-
state_new.version = action.payload.version;
|
|
427
|
-
return state_new;
|
|
428
|
-
break;
|
|
429
|
-
default:
|
|
430
|
-
break;
|
|
431
|
-
}
|
|
432
|
-
} catch(e){
|
|
433
|
-
}
|
|
434
|
-
var state_new = Lodash.clone(state);
|
|
435
|
-
return state_new;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
Test.subscribe(function(){
|
|
439
|
-
if(Cluster.isMaster){
|
|
440
|
-
var name = 'm';
|
|
441
|
-
} else {
|
|
442
|
-
var name = Cluster.worker.id;
|
|
443
|
-
}
|
|
444
|
-
console.log(name + ' | ' + JSON.stringify(Test.getState()));
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
if(Cluster.isMaster){
|
|
448
|
-
for(var i=0; i < 2; i++){
|
|
449
|
-
setTimeout(function(){Cluster.fork();}, i*8000);
|
|
450
|
-
}
|
|
451
|
-
var i = 0;
|
|
452
|
-
setInterval(function(){
|
|
453
|
-
Test.dispatch({type:'TASK', payload: {version:'OneRemoteMasterTest'+i}});
|
|
454
|
-
i++;
|
|
455
|
-
}, 11000);
|
|
456
|
-
} else {
|
|
457
|
-
var i = 0;
|
|
458
|
-
setInterval(function(){
|
|
459
|
-
Test.dispatch({type:'TASK', payload: {version:'OneRemoteWorkerTest'+i}});
|
|
460
|
-
i++;
|
|
461
|
-
}, 22000+(Cluster.worker.id*1500), i);
|
|
462
|
-
}
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
## Warning
|
|
466
|
-
|
|
467
|
-
Encryption (crypto.createCipheriv) and Decryption (crypto.createDecipheriv) features have been marked as deprecated in Node v12. I updated these functions in version 1.7.0, but if you used a backup of the storage to disk, you will not be able to download it.
|
|
468
|
-
|
|
469
|
-
## LICENSE
|
|
470
|
-
|
|
471
|
-
MIT
|
|
1
|
+
# Redux Cluster 2.0
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/redux-cluster)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](http://www.typescriptlang.org/)
|
|
6
|
+
|
|
7
|
+
A modern TypeScript library for synchronizing Redux stores across multiple processes and machines using TCP, Unix Domain Sockets, and IPC.
|
|
8
|
+
|
|
9
|
+
## 🌟 Key Features
|
|
10
|
+
|
|
11
|
+
- 🔄 **Real-time State Synchronization** across multiple processes/machines
|
|
12
|
+
- 🌐 **Multiple Transport Options**: TCP, Unix Domain Sockets, IPC
|
|
13
|
+
- 📡 **Bidirectional Communication** - any node can dispatch actions
|
|
14
|
+
- 🔒 **Built-in Security** with authentication and IP banning
|
|
15
|
+
- ⚡ **High Performance** with optimized networking and compression
|
|
16
|
+
- 🏗️ **Master-Slave Architecture** with automatic leader election
|
|
17
|
+
- 🔧 **TypeScript First** with comprehensive type definitions
|
|
18
|
+
- 🎯 **Redux Compatible** - works with existing Redux ecosystem
|
|
19
|
+
|
|
20
|
+
## 🏛️ Architecture Overview
|
|
21
|
+
|
|
22
|
+
Redux Cluster implements a master-slave architecture where one server manages the authoritative state and distributes updates to all connected clients:
|
|
23
|
+
|
|
24
|
+
```ascii
|
|
25
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
26
|
+
│ Redux Cluster Network │
|
|
27
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
28
|
+
│ │
|
|
29
|
+
│ ┌─────────────┐ TCP/Socket ┌─────────────┐ │
|
|
30
|
+
│ │ Client A │◄─────────────────────────────►│ Server │ │
|
|
31
|
+
│ │ (Worker) │ │ (Master) │ │
|
|
32
|
+
│ └─────────────┘ │ │ │
|
|
33
|
+
│ │ │ │
|
|
34
|
+
│ ┌─────────────┐ TCP/Socket │ │ │
|
|
35
|
+
│ │ Client B │◄─────────────────────────────►│ │ │
|
|
36
|
+
│ │ (Worker) │ │ │ │
|
|
37
|
+
│ └─────────────┘ └─────────────┘ │
|
|
38
|
+
│ │ │
|
|
39
|
+
│ ┌─────────────┐ TCP/Socket │ │
|
|
40
|
+
│ │ Client C │◄─────────────────────────────────────┘ │
|
|
41
|
+
│ │ (Worker) │ │
|
|
42
|
+
│ └─────────────┘ │
|
|
43
|
+
│ │
|
|
44
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Data Flow
|
|
48
|
+
|
|
49
|
+
```ascii
|
|
50
|
+
┌─────────────┐ 1. Action ┌─────────────┐ 2. Process ┌─────────────┐
|
|
51
|
+
│ Client │─────────────────►│ Server │────────────────►│ Redux │
|
|
52
|
+
│ │ │ (Master) │ │ Store │
|
|
53
|
+
└─────────────┘ └─────────────┘ └─────────────┘
|
|
54
|
+
▲ │ │
|
|
55
|
+
│ ▼ │
|
|
56
|
+
│ 4. State Update ┌─────────────┐ 3. State Changed │
|
|
57
|
+
└──────────────────────────│ Broadcast │◄─────────────────────┘
|
|
58
|
+
│ Engine │
|
|
59
|
+
└─────────────┘
|
|
60
|
+
│
|
|
61
|
+
▼
|
|
62
|
+
┌─────────────────────┐
|
|
63
|
+
│ All Clients │
|
|
64
|
+
│ (Auto-sync) │
|
|
65
|
+
└─────────────────────┘
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 🚀 Quick Start
|
|
69
|
+
|
|
70
|
+
### 1. Installation
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm install redux-cluster redux
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 2. Basic TCP Example
|
|
77
|
+
|
|
78
|
+
**Server (Master):**
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
const { createStore } = require('redux-cluster');
|
|
82
|
+
|
|
83
|
+
// Simple counter reducer
|
|
84
|
+
const counterReducer = (state = { counter: 0 }, action) => {
|
|
85
|
+
switch (action.type) {
|
|
86
|
+
case 'INCREMENT': return { counter: state.counter + 1 };
|
|
87
|
+
case 'DECREMENT': return { counter: state.counter - 1 };
|
|
88
|
+
default: return state;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Create store and server
|
|
93
|
+
const store = createStore(counterReducer);
|
|
94
|
+
const server = store.createServer({ port: 8080 });
|
|
95
|
+
|
|
96
|
+
console.log('Server started on port 8080');
|
|
97
|
+
|
|
98
|
+
// Server can dispatch actions
|
|
99
|
+
store.dispatch({ type: 'INCREMENT' });
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Client (Worker):**
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
const { createStore } = require('redux-cluster');
|
|
106
|
+
|
|
107
|
+
const store = createStore(counterReducer);
|
|
108
|
+
const client = store.createClient({
|
|
109
|
+
host: 'localhost',
|
|
110
|
+
port: 8080
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Client receives all state updates automatically
|
|
114
|
+
store.subscribe(() => {
|
|
115
|
+
console.log('New state:', store.getState());
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Client can also dispatch actions
|
|
119
|
+
store.dispatch({ type: 'INCREMENT' });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 🌐 Transport Options
|
|
123
|
+
|
|
124
|
+
Redux Cluster supports multiple transport mechanisms:
|
|
125
|
+
|
|
126
|
+
### TCP (Network)
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
// Server
|
|
130
|
+
const server = store.createServer({
|
|
131
|
+
host: 'localhost',
|
|
132
|
+
port: 8080
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Client
|
|
136
|
+
const client = store.createClient({
|
|
137
|
+
host: 'localhost',
|
|
138
|
+
port: 8080
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Unix Domain Sockets (Local)
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
// Server
|
|
146
|
+
const server = store.createServer({
|
|
147
|
+
path: '/tmp/redux-cluster.sock'
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Client
|
|
151
|
+
const client = store.createClient({
|
|
152
|
+
path: '/tmp/redux-cluster.sock'
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### IPC (Node.js Cluster)
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
import cluster from 'cluster';
|
|
160
|
+
|
|
161
|
+
if (cluster.isMaster) {
|
|
162
|
+
const store = createStore(reducer);
|
|
163
|
+
cluster.fork(); // Start worker
|
|
164
|
+
} else {
|
|
165
|
+
const store = createStore(reducer);
|
|
166
|
+
// IPC automatically enabled in cluster workers
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 🔧 Configuration Options
|
|
171
|
+
|
|
172
|
+
### Server Configuration
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
const server = store.createServer({
|
|
176
|
+
host: 'localhost', // TCP host
|
|
177
|
+
port: 8080, // TCP port
|
|
178
|
+
path: '/tmp/app.sock', // Unix socket path
|
|
179
|
+
logins: { // Authentication
|
|
180
|
+
'user1': 'password1',
|
|
181
|
+
'user2': 'password2'
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Client Configuration
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
const client = store.createClient({
|
|
190
|
+
host: 'localhost', // TCP host
|
|
191
|
+
port: 8080, // TCP port
|
|
192
|
+
path: '/tmp/app.sock', // Unix socket path
|
|
193
|
+
login: 'user1', // Authentication
|
|
194
|
+
password: 'password1'
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Store Configuration
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const store = createStore(reducer, {
|
|
202
|
+
mode: 'action', // 'action' | 'snapshot'
|
|
203
|
+
serializationMode: 'json', // 'json' | 'protoobject'
|
|
204
|
+
debug: false, // Enable debug logging
|
|
205
|
+
resync: 30000 // Resync interval (ms)
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## 📊 Synchronization Modes
|
|
210
|
+
|
|
211
|
+
### Action Mode (Default)
|
|
212
|
+
|
|
213
|
+
Actions are distributed and replayed on all nodes:
|
|
214
|
+
|
|
215
|
+
```ascii
|
|
216
|
+
Client A: dispatch(ACTION) ──► Server ──► broadcast(ACTION) ──► All Clients
|
|
217
|
+
│
|
|
218
|
+
▼
|
|
219
|
+
Apply ACTION to master state
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Snapshot Mode
|
|
223
|
+
|
|
224
|
+
Complete state snapshots are distributed:
|
|
225
|
+
|
|
226
|
+
```ascii
|
|
227
|
+
Client A: dispatch(ACTION) ──► Server ──► calculate new state ──► broadcast(STATE) ──► All Clients
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## 🔒 Security Features
|
|
231
|
+
|
|
232
|
+
### Authentication
|
|
233
|
+
|
|
234
|
+
```javascript
|
|
235
|
+
const server = store.createServer({
|
|
236
|
+
logins: {
|
|
237
|
+
'api-service': 'secret-key-123',
|
|
238
|
+
'worker-pool': 'another-secret'
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const client = store.createClient({
|
|
243
|
+
login: 'api-service',
|
|
244
|
+
password: 'secret-key-123'
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### IP Banning
|
|
249
|
+
|
|
250
|
+
Automatic IP banning after failed authentication attempts:
|
|
251
|
+
|
|
252
|
+
- 5+ failed attempts = 3 hour ban
|
|
253
|
+
- Automatic cleanup of expired bans
|
|
254
|
+
- Configurable ban policies
|
|
255
|
+
|
|
256
|
+
## 🎮 Examples
|
|
257
|
+
|
|
258
|
+
See the [examples/](./examples/) directory for complete working examples:
|
|
259
|
+
|
|
260
|
+
- **[TCP Transport](./examples/tcp/)** - Network communication
|
|
261
|
+
- **[File Socket](./examples/file-socket/)** - Local IPC via Unix sockets
|
|
262
|
+
- **[Basic Store](./examples/basic/)** - Local Redux store without networking
|
|
263
|
+
|
|
264
|
+
Each example includes a README with step-by-step instructions.
|
|
265
|
+
|
|
266
|
+
## 🧪 Testing
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
# Run all tests
|
|
270
|
+
npm test
|
|
271
|
+
|
|
272
|
+
# Run specific test suites
|
|
273
|
+
npm run test:unit # Unit tests
|
|
274
|
+
npm run test:transport # Transport integration tests
|
|
275
|
+
|
|
276
|
+
# Build and test
|
|
277
|
+
npm run build
|
|
278
|
+
npm run lint
|
|
279
|
+
|
|
280
|
+
# Run full integration tests (includes Docker)
|
|
281
|
+
npm run test:integration-full
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## 📈 Performance
|
|
285
|
+
|
|
286
|
+
Redux Cluster is optimized for high-throughput scenarios:
|
|
287
|
+
|
|
288
|
+
- **Compression**: gzip compression for all network traffic
|
|
289
|
+
- **Binary Protocol**: Efficient binary serialization options
|
|
290
|
+
- **Connection Pooling**: Reuse connections where possible
|
|
291
|
+
- **Minimal Overhead**: < 1ms latency for local sockets
|
|
292
|
+
|
|
293
|
+
Benchmark results:
|
|
294
|
+
|
|
295
|
+
- TCP: ~10,000 actions/sec
|
|
296
|
+
- Unix Sockets: ~50,000 actions/sec
|
|
297
|
+
- IPC: ~100,000 actions/sec
|
|
298
|
+
|
|
299
|
+
## 🗺️ Roadmap
|
|
300
|
+
|
|
301
|
+
- [ ] **Redis Transport** - Redis pub/sub for clustering
|
|
302
|
+
- [ ] **WebSocket Transport** - Browser client support
|
|
303
|
+
- [ ] **Conflict Resolution** - CRDT-based conflict resolution
|
|
304
|
+
- [ ] **Persistence Layer** - Automatic state persistence
|
|
305
|
+
- [ ] **Monitoring Dashboard** - Real-time cluster monitoring
|
|
306
|
+
- [ ] **Load Balancing** - Multiple master support
|
|
307
|
+
|
|
308
|
+
## 🤝 Contributing
|
|
309
|
+
|
|
310
|
+
Contributions are welcome! Please read our [Contributing Guidelines](./CONTRIBUTING.md) and [Code of Conduct](./CODE_OF_CONDUCT.md).
|
|
311
|
+
|
|
312
|
+
### Development Setup
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
git clone https://github.com/siarheidudko/redux-cluster.git
|
|
316
|
+
cd redux-cluster
|
|
317
|
+
npm install
|
|
318
|
+
npm run build
|
|
319
|
+
npm test
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## 📄 License
|
|
323
|
+
|
|
324
|
+
MIT License - see [LICENSE](./LICENSE) file for details.
|
|
325
|
+
|
|
326
|
+
## 🆘 Support
|
|
327
|
+
|
|
328
|
+
- 📝 **Issues**: [GitHub Issues](https://github.com/siarheidudko/redux-cluster/issues)
|
|
329
|
+
- 💬 **Discussions**: [GitHub Discussions](https://github.com/siarheidudko/redux-cluster/discussions)
|
|
330
|
+
- 📧 **Email**: [siarhei@dudko.dev](mailto:siarhei@dudko.dev)
|
|
331
|
+
|
|
332
|
+
## 💝 Support This Project
|
|
333
|
+
|
|
334
|
+
If Redux Cluster helps you build amazing applications, consider supporting its development:
|
|
335
|
+
|
|
336
|
+
- ☕ **[Buy me a coffee](https://www.buymeacoffee.com/dudko.dev)**
|
|
337
|
+
- 💳 **[PayPal](https://paypal.me/dudkodev)**
|
|
338
|
+
- 🎯 **[Patreon](https://patreon.com/dudko_dev)**
|
|
339
|
+
- 🌐 **[More options](http://dudko.dev/donate)**
|
|
340
|
+
|
|
341
|
+
Your support helps maintain and improve Redux Cluster for the entire community!
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
**Made with ❤️ by [Siarhei Dudko](https://github.com/siarheidudko)**
|