shuttlepro-shared 1.1.72 → 1.1.74
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/config/redis.js +53 -12
- package/config/socket.js +35 -35
- package/package.json +1 -1
package/config/redis.js
CHANGED
|
@@ -3,16 +3,19 @@ require("dotenv").config();
|
|
|
3
3
|
|
|
4
4
|
const REDIS_URL = process.env.REDIS_URL || "redis://localhost:6379";
|
|
5
5
|
|
|
6
|
-
// ✅ Create
|
|
6
|
+
// ✅ Create main Redis client
|
|
7
7
|
const client = createClient({
|
|
8
8
|
url: REDIS_URL,
|
|
9
|
-
socket: { reconnectStrategy: (retries) => Math.min(retries * 50, 1000) }, // Exponential backoff
|
|
9
|
+
socket: { reconnectStrategy: (retries) => Math.min(retries * 50, 1000) }, // Exponential backoff
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
+
// ✅ Create separate Pub/Sub clients
|
|
13
|
+
const publisher = client.duplicate();
|
|
14
|
+
const subscriber = client.duplicate();
|
|
15
|
+
|
|
12
16
|
// ✅ Handle Redis Connection Events
|
|
13
17
|
client.on("error", (err) => console.error("❌ Redis Error:", err));
|
|
14
18
|
client.on("connect", () => console.log("✅ Redis Connected"));
|
|
15
|
-
client.on("reconnecting", () => console.warn("⚠️ Redis Reconnecting..."));
|
|
16
19
|
client.on("ready", () => console.log("🚀 Redis Ready to use"));
|
|
17
20
|
client.on("end", () => console.log("❗ Redis Connection Closed"));
|
|
18
21
|
|
|
@@ -21,12 +24,46 @@ const connectRedis = async () => {
|
|
|
21
24
|
if (!client.isOpen) {
|
|
22
25
|
try {
|
|
23
26
|
await client.connect();
|
|
27
|
+
await publisher.connect();
|
|
28
|
+
await subscriber.connect();
|
|
24
29
|
} catch (err) {
|
|
25
30
|
console.error("❌ Failed to connect to Redis:", err);
|
|
26
31
|
}
|
|
27
32
|
}
|
|
28
33
|
};
|
|
29
34
|
|
|
35
|
+
/**
|
|
36
|
+
* ✅ Publish Data to a Channel
|
|
37
|
+
* @param {string} channel - The Redis Pub/Sub channel
|
|
38
|
+
* @param {any} message - The message to send
|
|
39
|
+
*/
|
|
40
|
+
const publishToChannel = async (channel, message) => {
|
|
41
|
+
try {
|
|
42
|
+
await connectRedis();
|
|
43
|
+
await publisher.publish(channel, JSON.stringify(message));
|
|
44
|
+
console.log(`📢 Message published to channel: ${channel}`);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error("❌ Error publishing message:", err);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* ✅ Subscribe & Listen for Messages
|
|
52
|
+
* @param {string} channel - The Redis Pub/Sub channel
|
|
53
|
+
* @param {function} callback - Callback function to handle messages
|
|
54
|
+
*/
|
|
55
|
+
const subscribeToChannel = async (channel, callback) => {
|
|
56
|
+
try {
|
|
57
|
+
await connectRedis();
|
|
58
|
+
await subscriber.subscribe(channel, (message) => {
|
|
59
|
+
console.log(`📥 Message received on channel: ${channel}`);
|
|
60
|
+
callback(JSON.parse(message));
|
|
61
|
+
});
|
|
62
|
+
} catch (err) {
|
|
63
|
+
console.error("❌ Error subscribing to channel:", err);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
30
67
|
/**
|
|
31
68
|
* ✅ Set Data in Redis (Supports String & Hash)
|
|
32
69
|
* @param {string} key - The Redis key
|
|
@@ -91,29 +128,33 @@ const deleteRedisData = async (key, field = null) => {
|
|
|
91
128
|
/**
|
|
92
129
|
* ✅ Graceful Shutdown Handling
|
|
93
130
|
*/
|
|
94
|
-
const
|
|
95
|
-
if (client.isOpen)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
131
|
+
const closeClients = async () => {
|
|
132
|
+
if (client.isOpen) await client.quit();
|
|
133
|
+
if (publisher.isOpen) await publisher.quit();
|
|
134
|
+
if (subscriber.isOpen) await subscriber.quit();
|
|
135
|
+
console.log("❗ Redis Clients Disconnected Gracefully");
|
|
99
136
|
};
|
|
100
137
|
|
|
101
138
|
// ✅ Ensure Redis disconnects properly on process exit
|
|
102
|
-
process.on("exit",
|
|
139
|
+
process.on("exit", closeClients);
|
|
103
140
|
process.on("SIGINT", async () => {
|
|
104
|
-
await
|
|
141
|
+
await closeClients();
|
|
105
142
|
process.exit();
|
|
106
143
|
});
|
|
107
144
|
process.on("SIGTERM", async () => {
|
|
108
|
-
await
|
|
145
|
+
await closeClients();
|
|
109
146
|
process.exit();
|
|
110
147
|
});
|
|
111
148
|
|
|
112
149
|
// ✅ Export Functions
|
|
113
150
|
module.exports = {
|
|
114
|
-
client,
|
|
151
|
+
client,
|
|
152
|
+
publisher,
|
|
153
|
+
subscriber,
|
|
115
154
|
setRedisData,
|
|
116
155
|
getRedisData,
|
|
117
156
|
deleteRedisData,
|
|
157
|
+
publishToChannel,
|
|
158
|
+
subscribeToChannel,
|
|
118
159
|
connectRedis,
|
|
119
160
|
};
|
package/config/socket.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { Server } = require("socket.io");
|
|
2
|
-
const {
|
|
2
|
+
const { publisher, subscriber, connectRedis } = require("./redis"); // Use separate Redis Pub/Sub clients
|
|
3
3
|
require("dotenv").config();
|
|
4
4
|
|
|
5
5
|
let io;
|
|
@@ -16,40 +16,33 @@ const initializeSocket = async (
|
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
//
|
|
19
|
+
// Return existing namespace if already initialized
|
|
20
20
|
if (namespaceSockets[namespaceParam]) {
|
|
21
|
-
console.log(`⚡ Namespace ${namespaceParam} already initialized`);
|
|
22
21
|
return namespaceSockets[namespaceParam];
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
// Create
|
|
24
|
+
// Create and store namespace
|
|
26
25
|
const namespace = io.of(`/${namespaceParam}`);
|
|
27
26
|
namespaceSockets[namespaceParam] = namespace;
|
|
28
|
-
console.log(`✅ WebSocket Namespace Initialized: /${namespaceParam}`);
|
|
29
27
|
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
await subClient.connect();
|
|
33
|
-
await subClient.subscribe(redisChannel);
|
|
28
|
+
// Ensure Redis is connected
|
|
29
|
+
await connectRedis();
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
message
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
// Subscribe to Redis events for this namespace
|
|
32
|
+
await subscriber.subscribe(redisChannel, (message) => {
|
|
33
|
+
try {
|
|
34
|
+
const { workspaceId, event, data } = JSON.parse(message);
|
|
35
|
+
namespace.to(workspaceId).emit(event, data);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error("❌ Error parsing Redis message:", err);
|
|
38
|
+
}
|
|
43
39
|
});
|
|
44
40
|
|
|
45
|
-
// Handle socket connections
|
|
41
|
+
// Handle new socket connections
|
|
46
42
|
namespace.on("connection", (socket) => {
|
|
47
43
|
const { workspaceId } = socket.handshake.query;
|
|
48
44
|
|
|
49
45
|
if (!workspaceId) {
|
|
50
|
-
console.warn(
|
|
51
|
-
`❌ Client ${socket.id} rejected due to missing workspaceId`
|
|
52
|
-
);
|
|
53
46
|
socket.disconnect(true);
|
|
54
47
|
return;
|
|
55
48
|
}
|
|
@@ -62,33 +55,40 @@ const initializeSocket = async (
|
|
|
62
55
|
|
|
63
56
|
socket.on("disconnect", () => {
|
|
64
57
|
console.log(
|
|
65
|
-
`❌ Client disconnected: ${socket.id} (Workspace: ${workspaceId})
|
|
58
|
+
`❌ Client disconnected: ${socket.id} (Workspace: ${workspaceId})`
|
|
66
59
|
);
|
|
60
|
+
socket.leave(workspaceId);
|
|
67
61
|
});
|
|
68
62
|
});
|
|
69
63
|
|
|
70
64
|
return namespace;
|
|
71
65
|
};
|
|
72
66
|
|
|
67
|
+
/**
|
|
68
|
+
* ✅ Publish Event to Redis Channel
|
|
69
|
+
* @param {object} params - Event data
|
|
70
|
+
* @param {string} params.workspaceId - Target workspace ID
|
|
71
|
+
* @param {string} params.event - Event name
|
|
72
|
+
* @param {any} params.data - Event data
|
|
73
|
+
* @param {string} [params.redisChannel="socket_events"] - Redis channel (optional)
|
|
74
|
+
*/
|
|
73
75
|
const sendEventToServer = async ({
|
|
74
|
-
namespace = "conversation",
|
|
75
76
|
workspaceId,
|
|
76
77
|
event,
|
|
77
78
|
data,
|
|
78
79
|
redisChannel = "socket_events",
|
|
79
80
|
}) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
await redisClient.disconnect();
|
|
81
|
+
try {
|
|
82
|
+
await publisher.publish(
|
|
83
|
+
redisChannel,
|
|
84
|
+
JSON.stringify({ workspaceId, event, data })
|
|
85
|
+
);
|
|
86
|
+
console.log(
|
|
87
|
+
`📢 Event published to Redis: ${event} (Workspace: ${workspaceId})`
|
|
88
|
+
);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error("❌ Error publishing to Redis:", err);
|
|
91
|
+
}
|
|
92
92
|
};
|
|
93
93
|
|
|
94
94
|
module.exports = { initializeSocket, sendEventToServer };
|