redux-cluster-ws 2.0.1 → 2.0.2

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.
@@ -1,190 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Cross-library WebSocket Client
5
- *
6
- * This client connects to the cross-library server via WebSocket
7
- * while the server also handles cluster workers via IPC/TCP
8
- */
9
-
10
- const { createStore } = require("../dist/cjs/index.js");
11
-
12
- // Same reducer as server
13
- function todoReducer(
14
- state = { todos: [], users: [], stats: { total: 0 } },
15
- action
16
- ) {
17
- switch (action.type) {
18
- case "ADD_TODO":
19
- return {
20
- ...state,
21
- todos: [
22
- ...state.todos,
23
- {
24
- id: Date.now(),
25
- text: action.payload.text,
26
- completed: false,
27
- createdBy: action.payload.user || "anonymous",
28
- timestamp: new Date().toISOString(),
29
- },
30
- ],
31
- stats: { total: state.stats.total + 1 },
32
- };
33
-
34
- case "TOGGLE_TODO":
35
- return {
36
- ...state,
37
- todos: state.todos.map((todo) =>
38
- todo.id === action.payload.id
39
- ? { ...todo, completed: !todo.completed }
40
- : todo
41
- ),
42
- };
43
-
44
- case "ADD_USER":
45
- const userExists = state.users.find(
46
- (u) => u.name === action.payload.name
47
- );
48
- if (userExists) return state;
49
-
50
- return {
51
- ...state,
52
- users: [
53
- ...state.users,
54
- {
55
- id: Date.now(),
56
- name: action.payload.name,
57
- joinedAt: new Date().toISOString(),
58
- type: action.payload.type || "web",
59
- },
60
- ],
61
- };
62
-
63
- case "REMOVE_USER":
64
- return {
65
- ...state,
66
- users: state.users.filter((u) => u.id !== action.payload.id),
67
- };
68
-
69
- default:
70
- return state;
71
- }
72
- }
73
-
74
- console.log("🌐 Starting WebSocket client for cross-library demo...");
75
-
76
- // Create store
77
- const store = createStore(todoReducer);
78
-
79
- // Connect to WebSocket server
80
- store.createWSClient({
81
- host: "ws://127.0.0.1",
82
- port: 8890,
83
- login: "web-client",
84
- password: "web123",
85
- });
86
-
87
- const clientName = `WebSocket Client ${process.pid}`;
88
-
89
- // Wait for connection and add user
90
- setTimeout(() => {
91
- if (store.connected) {
92
- store.dispatch({
93
- type: "ADD_USER",
94
- payload: { name: clientName, type: "web" },
95
- });
96
-
97
- console.log(`āœ… Connected as "${clientName}"`);
98
- }
99
- }, 1000);
100
-
101
- // Subscribe to state changes
102
- store.subscribe(() => {
103
- const state = store.getState();
104
- console.log(`\\nšŸ“Š Current state:`);
105
- console.log(` Todos: ${state.todos.length}`);
106
- console.log(` Users: ${state.users.length}`);
107
- console.log(` Total created: ${state.stats.total}`);
108
-
109
- if (state.todos.length > 0) {
110
- console.log(`\\nšŸ“ Recent todos:`);
111
- state.todos.slice(-3).forEach((todo) => {
112
- const status = todo.completed ? "āœ…" : "ā³";
113
- console.log(` ${status} "${todo.text}" by ${todo.createdBy}`);
114
- });
115
- }
116
-
117
- if (state.users.length > 0) {
118
- console.log(`\\nšŸ‘„ Connected users:`);
119
- state.users.forEach((user) => {
120
- const icon = user.type === "cluster" ? "šŸ”§" : "🌐";
121
- console.log(` ${icon} ${user.name} (${user.type})`);
122
- });
123
- }
124
- });
125
-
126
- // Interactive commands
127
- process.stdin.setEncoding("utf8");
128
- console.log("\\nšŸ“‹ Commands:");
129
- console.log(' Type "add <text>" to add a todo');
130
- console.log(' Type "toggle <id>" to toggle a todo');
131
- console.log(' Type "list" to show current state');
132
- console.log(' Type "quit" to exit');
133
- console.log("\\n> ");
134
-
135
- process.stdin.on("data", (input) => {
136
- const command = input.trim();
137
-
138
- if (command.startsWith("add ")) {
139
- const text = command.substring(4);
140
- if (text) {
141
- store.dispatch({
142
- type: "ADD_TODO",
143
- payload: {
144
- text,
145
- user: clientName,
146
- },
147
- });
148
- console.log(`āœ… Added todo: "${text}"`);
149
- }
150
- } else if (command.startsWith("toggle ")) {
151
- const id = parseInt(command.substring(7));
152
- if (id) {
153
- store.dispatch({
154
- type: "TOGGLE_TODO",
155
- payload: { id },
156
- });
157
- console.log(`šŸ”„ Toggled todo ${id}`);
158
- }
159
- } else if (command === "list") {
160
- const state = store.getState();
161
- console.log("\\nšŸ“‹ Current todos:");
162
- state.todos.forEach((todo) => {
163
- const status = todo.completed ? "āœ…" : "ā³";
164
- console.log(
165
- ` ${todo.id}: ${status} "${todo.text}" by ${todo.createdBy}`
166
- );
167
- });
168
- } else if (command === "quit") {
169
- console.log("šŸ‘‹ Goodbye!");
170
- process.exit(0);
171
- } else if (command) {
172
- console.log(
173
- 'āŒ Unknown command. Use "add <text>", "toggle <id>", "list", or "quit"'
174
- );
175
- }
176
-
177
- process.stdout.write("> ");
178
- });
179
-
180
- // Cleanup on exit
181
- process.on("SIGINT", () => {
182
- console.log("\\nšŸ‘‹ Disconnecting...");
183
- if (store.connected) {
184
- store.dispatch({
185
- type: "REMOVE_USER",
186
- payload: { name: clientName },
187
- });
188
- }
189
- process.exit(0);
190
- });
@@ -1,213 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Cross-library Example: Redux-Cluster server + Redux-Cluster-WS client
5
- *
6
- * This example demonstrates how redux-cluster (IPC/TCP) can work alongside
7
- * redux-cluster-ws (WebSocket) to create a hybrid architecture where:
8
- * - Node.js processes communicate via IPC/TCP (redux-cluster)
9
- * - Web clients communicate via WebSocket (redux-cluster-ws)
10
- */
11
-
12
- const { createStore } = require("redux-cluster");
13
- const { server } = require("../dist/cjs/index.js");
14
- const cluster = require("cluster");
15
-
16
- // Shared reducer
17
- function todoReducer(
18
- state = { todos: [], users: [], stats: { total: 0 } },
19
- action
20
- ) {
21
- switch (action.type) {
22
- case "ADD_TODO":
23
- return {
24
- ...state,
25
- todos: [
26
- ...state.todos,
27
- {
28
- id: Date.now(),
29
- text: action.payload.text,
30
- completed: false,
31
- createdBy: action.payload.user || "anonymous",
32
- timestamp: new Date().toISOString(),
33
- },
34
- ],
35
- stats: { total: state.stats.total + 1 },
36
- };
37
-
38
- case "TOGGLE_TODO":
39
- return {
40
- ...state,
41
- todos: state.todos.map((todo) =>
42
- todo.id === action.payload.id
43
- ? { ...todo, completed: !todo.completed }
44
- : todo
45
- ),
46
- };
47
-
48
- case "ADD_USER":
49
- const userExists = state.users.find(
50
- (u) => u.name === action.payload.name
51
- );
52
- if (userExists) return state;
53
-
54
- return {
55
- ...state,
56
- users: [
57
- ...state.users,
58
- {
59
- id: Date.now(),
60
- name: action.payload.name,
61
- joinedAt: new Date().toISOString(),
62
- type: action.payload.type || "web", // 'web' or 'cluster'
63
- },
64
- ],
65
- };
66
-
67
- case "REMOVE_USER":
68
- return {
69
- ...state,
70
- users: state.users.filter((u) => u.id !== action.payload.id),
71
- };
72
-
73
- default:
74
- return state;
75
- }
76
- }
77
-
78
- if (cluster.isMaster) {
79
- console.log("šŸš€ Starting cross-library demo...");
80
-
81
- // Create main store with redux-cluster
82
- const store = createStore(todoReducer, {
83
- mode: "snapshot",
84
- enableObjectStream: true, // Use protoobject for better performance
85
- });
86
-
87
- // Add WebSocket server capability
88
- server(store);
89
-
90
- // Start WebSocket server for web clients
91
- store.createWSServer({
92
- host: "127.0.0.1",
93
- port: 8890,
94
- logins: {
95
- "web-client": "web123",
96
- admin: "admin123",
97
- },
98
- });
99
-
100
- console.log("āœ… WebSocket server started on port 8890");
101
- console.log("šŸ”§ Web clients can connect to ws://127.0.0.1:8890");
102
-
103
- // Fork cluster workers for internal processing
104
- const worker1 = cluster.fork();
105
- const worker2 = cluster.fork();
106
-
107
- console.log("āœ… Cluster workers started");
108
-
109
- // Add main process as admin user
110
- store.dispatch({
111
- type: "ADD_USER",
112
- payload: { name: "Main Process", type: "cluster" },
113
- });
114
-
115
- // Simulate periodic tasks from main process
116
- let counter = 0;
117
- setInterval(() => {
118
- store.dispatch({
119
- type: "ADD_TODO",
120
- payload: {
121
- text: `Scheduled task ${++counter} from main process`,
122
- user: "Main Process",
123
- },
124
- });
125
- }, 15000);
126
-
127
- // Log state changes
128
- store.subscribe(() => {
129
- const state = store.getState();
130
- console.log(
131
- `šŸ“Š State update: ${state.todos.length} todos, ${state.users.length} users`
132
- );
133
- });
134
-
135
- // Handle worker messages
136
- cluster.on("message", (worker, message) => {
137
- console.log(`šŸ’¬ Message from worker ${worker.process.pid}:`, message);
138
- });
139
-
140
- // Cleanup on exit
141
- process.on("SIGINT", () => {
142
- console.log("\\nšŸ›‘ Shutting down cross-library demo...");
143
- for (const id in cluster.workers) {
144
- cluster.workers[id].kill();
145
- }
146
- process.exit(0);
147
- });
148
- } else {
149
- // Worker process
150
- const store = createStore(todoReducer, {
151
- mode: "action",
152
- enableObjectStream: true,
153
- });
154
-
155
- // Connect to master via cluster IPC
156
- store.createClient({
157
- host: "master",
158
- });
159
-
160
- const workerId = process.pid;
161
- console.log(`šŸ‘· Worker ${workerId} started and connected to master`);
162
-
163
- // Add worker as user
164
- store.dispatch({
165
- type: "ADD_USER",
166
- payload: { name: `Worker ${workerId}`, type: "cluster" },
167
- });
168
-
169
- // Worker-specific tasks
170
- let taskCount = 0;
171
- setInterval(() => {
172
- if (Math.random() > 0.7) {
173
- // 30% chance
174
- store.dispatch({
175
- type: "ADD_TODO",
176
- payload: {
177
- text: `Background task ${++taskCount} from worker ${workerId}`,
178
- user: `Worker ${workerId}`,
179
- },
180
- });
181
- }
182
- }, 8000);
183
-
184
- // Send periodic status to master
185
- setInterval(() => {
186
- if (process.send) {
187
- process.send({
188
- type: "status",
189
- workerId,
190
- timestamp: new Date().toISOString(),
191
- memory: process.memoryUsage(),
192
- });
193
- }
194
- }, 30000);
195
-
196
- // Subscribe to state changes
197
- store.subscribe(() => {
198
- const state = store.getState();
199
- console.log(`šŸ‘· Worker ${workerId} sees: ${state.todos.length} todos`);
200
- });
201
- }
202
-
203
- console.log("\\nšŸ“‹ Instructions:");
204
- console.log(
205
- "1. This demo shows redux-cluster (IPC) + redux-cluster-ws (WebSocket)"
206
- );
207
- console.log("2. Main process and workers communicate via cluster IPC");
208
- console.log("3. Web clients can connect via WebSocket to the same store");
209
- console.log("4. Open examples/cross-library-browser.html to see web client");
210
- console.log(
211
- "5. Or run examples/cross-library-client.js for Node.js WebSocket client"
212
- );
213
- console.log("");
@@ -1,96 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Basic Redux-Cluster-WS Server Example
5
- *
6
- * This example demonstrates how to create a simple WebSocket server
7
- * that synchronizes Redux state across multiple clients.
8
- */
9
-
10
- const { createStore } = require("redux-cluster");
11
- const { server } = require("../dist/cjs/index.js");
12
-
13
- // Simple counter reducer
14
- function counterReducer(state = { count: 0, lastUpdate: null }, action) {
15
- switch (action.type) {
16
- case "INCREMENT":
17
- return {
18
- count: state.count + 1,
19
- lastUpdate: new Date().toISOString(),
20
- };
21
-
22
- case "DECREMENT":
23
- return {
24
- count: state.count - 1,
25
- lastUpdate: new Date().toISOString(),
26
- };
27
-
28
- case "RESET":
29
- return {
30
- count: 0,
31
- lastUpdate: new Date().toISOString(),
32
- };
33
-
34
- default:
35
- return state;
36
- }
37
- }
38
-
39
- console.log("šŸš€ Starting Redux-Cluster-WS Server Example...");
40
-
41
- // Create Redux store
42
- const store = createStore(counterReducer);
43
-
44
- // Add WebSocket server capability
45
- server(store);
46
-
47
- // Configure synchronization mode
48
- store.mode = "snapshot"; // Send full state on changes
49
-
50
- // Subscribe to state changes for logging
51
- store.subscribe(() => {
52
- const state = store.getState();
53
- console.log(
54
- `šŸ“Š State updated: count=${state.count}, lastUpdate=${state.lastUpdate}`
55
- );
56
- });
57
-
58
- // Start WebSocket server
59
- store.createWSServer({
60
- host: "0.0.0.0",
61
- port: 8088,
62
- logins: {
63
- admin: "password123",
64
- user: "secret456",
65
- demo: "demo",
66
- },
67
- });
68
-
69
- console.log("āœ… WebSocket server started on ws://localhost:8088");
70
- console.log("šŸ”‘ Available logins:");
71
- console.log(" - admin:password123");
72
- console.log(" - user:secret456");
73
- console.log(" - demo:demo");
74
- console.log("");
75
- console.log("šŸ’” Try connecting with the client example or browser!");
76
- console.log("");
77
-
78
- // Simulate some activity on the server
79
- let counter = 0;
80
- setInterval(() => {
81
- counter++;
82
-
83
- if (counter % 3 === 0) {
84
- store.dispatch({ type: "INCREMENT" });
85
- console.log("šŸŽÆ Server auto-increment");
86
- }
87
- }, 5000);
88
-
89
- // Handle graceful shutdown
90
- process.on("SIGINT", () => {
91
- console.log("\\nšŸ‘‹ Shutting down server...");
92
- process.exit(0);
93
- });
94
-
95
- console.log("šŸ”„ Server will auto-increment every 5 seconds");
96
- console.log("Press Ctrl+C to stop");