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 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 a single Redis client instance
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 for reconnections
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 closeClient = async () => {
95
- if (client.isOpen) {
96
- await client.quit();
97
- console.log("❗ Redis Disconnected Gracefully");
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", closeClient);
139
+ process.on("exit", closeClients);
103
140
  process.on("SIGINT", async () => {
104
- await closeClient();
141
+ await closeClients();
105
142
  process.exit();
106
143
  });
107
144
  process.on("SIGTERM", async () => {
108
- await closeClient();
145
+ await closeClients();
109
146
  process.exit();
110
147
  });
111
148
 
112
149
  // ✅ Export Functions
113
150
  module.exports = {
114
- client, // Export Redis client for reuse
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 { createClient } = require("redis");
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
- // If namespace is already initialized, return it
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 new namespace
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
- // Create Redis subscriber for this namespace
31
- const subClient = createClient({ url: process.env.REDIS_URL });
32
- await subClient.connect();
33
- await subClient.subscribe(redisChannel);
28
+ // Ensure Redis is connected
29
+ await connectRedis();
34
30
 
35
- subClient.on("message", (channel, message) => {
36
- console.log(
37
- `🔔 Redis Event on ${channel} for /${namespaceParam}:`,
38
- message
39
- );
40
- const { workspaceId, event, data } = JSON.parse(message);
41
-
42
- namespace.to(workspaceId).emit(event, data);
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 per namespace
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}) in /${namespaceParam}`
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
- const redisClient = createClient({ url: process.env.REDIS_URL });
81
- await redisClient.connect();
82
-
83
- console.log(
84
- `📤 Sending event '${event}' to namespace '/${namespace}' for workspace '${workspaceId}'`
85
- );
86
- await redisClient.publish(
87
- redisChannel,
88
- JSON.stringify({ workspaceId, event, data })
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shuttlepro-shared",
3
- "version": "1.1.72",
3
+ "version": "1.1.74",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {