@eleven-am/pondsocket 0.1.192 → 0.1.193
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/abstracts/redisClient.js +143 -195
- package/package.json +2 -2
package/abstracts/redisClient.js
CHANGED
|
@@ -33,7 +33,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
33
33
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
34
34
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
35
35
|
};
|
|
36
|
-
var _RedisClient_instances, _RedisClient_heartbeatInterval, _RedisClient_cleanupInterval, _RedisClient_instanceTtl, _RedisClient_redisClient, _RedisClient_pubClient, _RedisClient_subClient, _RedisClient_instanceId, _RedisClient_assignsPublisher, _RedisClient_presencePublisher, _RedisClient_userLeavesPublisher, _RedisClient_channelMessagePublisher, _RedisClient_stateSyncPublisher, _RedisClient_heartbeatTimer, _RedisClient_cleanupTimer, _RedisClient_presence_changes_channel_get, _RedisClient_assigns_changes_channel_get, _RedisClient_channel_messages_channel_get, _RedisClient_user_leaves_channel_get, _RedisClient_handleErrors, _RedisClient_registerInstance, _RedisClient_unregisterInstance, _RedisClient_cleanupDisconnectedClients,
|
|
36
|
+
var _RedisClient_instances, _RedisClient_heartbeatInterval, _RedisClient_cleanupInterval, _RedisClient_instanceTtl, _RedisClient_redisClient, _RedisClient_pubClient, _RedisClient_subClient, _RedisClient_instanceId, _RedisClient_assignsPublisher, _RedisClient_presencePublisher, _RedisClient_userLeavesPublisher, _RedisClient_channelMessagePublisher, _RedisClient_stateSyncPublisher, _RedisClient_heartbeatTimer, _RedisClient_cleanupTimer, _RedisClient_stateSyncInterval, _RedisClient_ttlBuffer, _RedisClient_presence_changes_channel_get, _RedisClient_assigns_changes_channel_get, _RedisClient_channel_messages_channel_get, _RedisClient_user_leaves_channel_get, _RedisClient_handleErrors, _RedisClient_registerInstance, _RedisClient_unregisterInstance, _RedisClient_cleanupDisconnectedClients, _RedisClient_startPeriodicCleanup, _RedisClient_startHeartbeat, _RedisClient_unsubscribeFromChannels, _RedisClient_subscribeToChannels, _RedisClient_handleRedisMessage, _RedisClient_getPresenceCacheChannel, _RedisClient_getAssignsCacheChannel, _RedisClient_subscribeToCacheChanges, _RedisClient_subscribeToChannelMessages, _RedisClient_subscribeToUserLeaves, _RedisClient_subscribeToStateSync, _RedisClient_publishPresenceChange, _RedisClient_publishAssignsChange, _RedisClient_publishChannelMessage, _RedisClient_publishUserLeave, _RedisClient_publishCacheMessage, _RedisClient_emitStateSyncEvent, _RedisClient_getActiveInstances, _RedisClient_getCachedInstances, _RedisClient_generateCache, _RedisClient_handleExit;
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
38
|
exports.RedisClient = void 0;
|
|
39
39
|
const pondsocket_common_1 = require("@eleven-am/pondsocket-common");
|
|
@@ -41,7 +41,7 @@ const ioredis_1 = __importDefault(require("ioredis"));
|
|
|
41
41
|
const redisError_1 = require("../errors/redisError");
|
|
42
42
|
class RedisClient {
|
|
43
43
|
constructor(config) {
|
|
44
|
-
var _a
|
|
44
|
+
var _a;
|
|
45
45
|
_RedisClient_instances.add(this);
|
|
46
46
|
_RedisClient_heartbeatInterval.set(this, void 0);
|
|
47
47
|
_RedisClient_cleanupInterval.set(this, void 0);
|
|
@@ -57,9 +57,14 @@ class RedisClient {
|
|
|
57
57
|
_RedisClient_stateSyncPublisher.set(this, void 0);
|
|
58
58
|
_RedisClient_heartbeatTimer.set(this, void 0);
|
|
59
59
|
_RedisClient_cleanupTimer.set(this, void 0);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
_RedisClient_stateSyncInterval.set(this, void 0);
|
|
61
|
+
_RedisClient_ttlBuffer.set(this, 5);
|
|
62
|
+
const baseTtl = (_a = config.instanceTtl) !== null && _a !== void 0 ? _a : 90;
|
|
63
|
+
const milliseconds = baseTtl * 1000;
|
|
64
|
+
__classPrivateFieldSet(this, _RedisClient_stateSyncInterval, milliseconds, "f");
|
|
65
|
+
__classPrivateFieldSet(this, _RedisClient_cleanupInterval, milliseconds * 2, "f");
|
|
66
|
+
__classPrivateFieldSet(this, _RedisClient_heartbeatInterval, milliseconds / 3, "f");
|
|
67
|
+
__classPrivateFieldSet(this, _RedisClient_instanceTtl, baseTtl + __classPrivateFieldGet(this, _RedisClient_ttlBuffer, "f"), "f");
|
|
63
68
|
__classPrivateFieldSet(this, _RedisClient_redisClient, new ioredis_1.default(config), "f");
|
|
64
69
|
__classPrivateFieldSet(this, _RedisClient_pubClient, new ioredis_1.default(config), "f");
|
|
65
70
|
__classPrivateFieldSet(this, _RedisClient_subClient, new ioredis_1.default(config), "f");
|
|
@@ -105,7 +110,7 @@ class RedisClient {
|
|
|
105
110
|
}
|
|
106
111
|
}
|
|
107
112
|
exports.RedisClient = RedisClient;
|
|
108
|
-
_RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = new WeakMap(), _RedisClient_instanceTtl = new WeakMap(), _RedisClient_redisClient = new WeakMap(), _RedisClient_pubClient = new WeakMap(), _RedisClient_subClient = new WeakMap(), _RedisClient_instanceId = new WeakMap(), _RedisClient_assignsPublisher = new WeakMap(), _RedisClient_presencePublisher = new WeakMap(), _RedisClient_userLeavesPublisher = new WeakMap(), _RedisClient_channelMessagePublisher = new WeakMap(), _RedisClient_stateSyncPublisher = new WeakMap(), _RedisClient_heartbeatTimer = new WeakMap(), _RedisClient_cleanupTimer = new WeakMap(), _RedisClient_instances = new WeakSet(), _RedisClient_presence_changes_channel_get = function _RedisClient_presence_changes_channel_get() {
|
|
113
|
+
_RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = new WeakMap(), _RedisClient_instanceTtl = new WeakMap(), _RedisClient_redisClient = new WeakMap(), _RedisClient_pubClient = new WeakMap(), _RedisClient_subClient = new WeakMap(), _RedisClient_instanceId = new WeakMap(), _RedisClient_assignsPublisher = new WeakMap(), _RedisClient_presencePublisher = new WeakMap(), _RedisClient_userLeavesPublisher = new WeakMap(), _RedisClient_channelMessagePublisher = new WeakMap(), _RedisClient_stateSyncPublisher = new WeakMap(), _RedisClient_heartbeatTimer = new WeakMap(), _RedisClient_cleanupTimer = new WeakMap(), _RedisClient_stateSyncInterval = new WeakMap(), _RedisClient_ttlBuffer = new WeakMap(), _RedisClient_instances = new WeakSet(), _RedisClient_presence_changes_channel_get = function _RedisClient_presence_changes_channel_get() {
|
|
109
114
|
return 'presence_changes';
|
|
110
115
|
}, _RedisClient_assigns_changes_channel_get = function _RedisClient_assigns_changes_channel_get() {
|
|
111
116
|
return 'assigns_changes';
|
|
@@ -119,31 +124,24 @@ _RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = n
|
|
|
119
124
|
__classPrivateFieldGet(this, _RedisClient_subClient, "f").on('error', (err) => console.error('Redis sub client error:', err));
|
|
120
125
|
}, _RedisClient_registerInstance = function _RedisClient_registerInstance() {
|
|
121
126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
122
|
-
const multi = __classPrivateFieldGet(this, _RedisClient_redisClient, "f").multi();
|
|
123
|
-
const now = Date.now().toString();
|
|
124
|
-
multi
|
|
125
|
-
.sadd('distributed_instances', __classPrivateFieldGet(this, _RedisClient_instanceId, "f"))
|
|
126
|
-
.set(`heartbeat:${__classPrivateFieldGet(this, _RedisClient_instanceId, "f")}`, now, 'EX', __classPrivateFieldGet(this, _RedisClient_instanceTtl, "f"))
|
|
127
|
-
.hset(`instance_metadata:${__classPrivateFieldGet(this, _RedisClient_instanceId, "f")}`, 'last_seen', now);
|
|
128
127
|
try {
|
|
129
|
-
|
|
128
|
+
const now = Date.now().toString();
|
|
129
|
+
yield __classPrivateFieldGet(this, _RedisClient_redisClient, "f").set(`heartbeat:${__classPrivateFieldGet(this, _RedisClient_instanceId, "f")}`, now, 'EX', __classPrivateFieldGet(this, _RedisClient_instanceTtl, "f"));
|
|
130
130
|
}
|
|
131
131
|
catch (error) {
|
|
132
|
-
throw new redisError_1.RedisError(
|
|
132
|
+
throw new redisError_1.RedisError(`Error registering instance: ${error}`);
|
|
133
133
|
}
|
|
134
134
|
});
|
|
135
135
|
}, _RedisClient_unregisterInstance = function _RedisClient_unregisterInstance() {
|
|
136
136
|
return __awaiter(this, arguments, void 0, function* (instanceId = __classPrivateFieldGet(this, _RedisClient_instanceId, "f")) {
|
|
137
137
|
const script = `
|
|
138
|
-
--
|
|
139
|
-
redis.call('SREM', 'distributed_instances', ARGV[1])
|
|
138
|
+
-- Delete heartbeat
|
|
140
139
|
redis.call('DEL', 'heartbeat:' .. ARGV[1])
|
|
141
|
-
redis.call('DEL', 'instance_metadata:' .. ARGV[1])
|
|
142
140
|
|
|
143
141
|
-- Delete all cache keys in one SCAN operation
|
|
144
142
|
local cursor = '0'
|
|
145
143
|
repeat
|
|
146
|
-
local result = redis.call('SCAN', cursor, 'MATCH', '
|
|
144
|
+
local result = redis.call('SCAN', cursor, 'MATCH', '*_cache:' .. ARGV[1] .. ':*', 'COUNT', 100)
|
|
147
145
|
cursor = result[1]
|
|
148
146
|
local keys = result[2]
|
|
149
147
|
if #keys > 0 then
|
|
@@ -163,56 +161,37 @@ _RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = n
|
|
|
163
161
|
}, _RedisClient_cleanupDisconnectedClients = function _RedisClient_cleanupDisconnectedClients() {
|
|
164
162
|
return __awaiter(this, void 0, void 0, function* () {
|
|
165
163
|
const script = `
|
|
166
|
-
--
|
|
167
|
-
local
|
|
168
|
-
local heartbeat = redis.call('GET', 'heartbeat:' .. instance_id)
|
|
169
|
-
local in_set = redis.call('SISMEMBER', 'distributed_instances', instance_id)
|
|
170
|
-
return heartbeat and in_set == 1
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
-- Get array of instance IDs passed as argument
|
|
174
|
-
local instance_ids = cjson.decode(ARGV[1])
|
|
175
|
-
|
|
176
|
-
-- Track affected channels and keys to delete
|
|
164
|
+
-- Array of instance IDs that have cache data but no heartbeat
|
|
165
|
+
local dead_instances = cjson.decode(ARGV[1])
|
|
177
166
|
local affected_channels = {}
|
|
178
167
|
local keys_to_delete = {}
|
|
179
168
|
local batch_size = 100
|
|
180
169
|
|
|
181
|
-
-- Process each instance
|
|
182
|
-
for _, instance_id in ipairs(
|
|
183
|
-
--
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
170
|
+
-- Process each dead instance
|
|
171
|
+
for _, instance_id in ipairs(dead_instances) do
|
|
172
|
+
-- Find and process all cache keys for this instance
|
|
173
|
+
local cache_cursor = '0'
|
|
174
|
+
repeat
|
|
175
|
+
local result = redis.call('SCAN', cache_cursor, 'MATCH', '*_cache:' .. instance_id .. ':*', 'COUNT', batch_size)
|
|
176
|
+
cache_cursor = result[1]
|
|
188
177
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
local result = redis.call('SCAN', cache_cursor, 'MATCH', '*_cache:' .. instance_id .. ':*', 'COUNT', batch_size)
|
|
196
|
-
cache_cursor = result[1]
|
|
178
|
+
for _, key in ipairs(result[2]) do
|
|
179
|
+
-- Extract channel info before deletion
|
|
180
|
+
local _, _, endpoint_id, channel_id = string.match(key, '_cache:[^:]+:([^:]+):([^:]+)')
|
|
181
|
+
if endpoint_id and channel_id then
|
|
182
|
+
affected_channels[endpoint_id .. ":" .. channel_id] = true
|
|
183
|
+
end
|
|
197
184
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
-- Add to deletion batch
|
|
206
|
-
table.insert(keys_to_delete, key)
|
|
207
|
-
|
|
208
|
-
-- If batch is full, process it
|
|
209
|
-
if #keys_to_delete >= batch_size then
|
|
210
|
-
redis.call('DEL', unpack(keys_to_delete))
|
|
211
|
-
keys_to_delete = {}
|
|
212
|
-
end
|
|
185
|
+
-- Add to deletion batch
|
|
186
|
+
table.insert(keys_to_delete, key)
|
|
187
|
+
|
|
188
|
+
-- If batch is full, process it
|
|
189
|
+
if #keys_to_delete >= batch_size then
|
|
190
|
+
redis.call('DEL', unpack(keys_to_delete))
|
|
191
|
+
keys_to_delete = {}
|
|
213
192
|
end
|
|
214
|
-
|
|
215
|
-
|
|
193
|
+
end
|
|
194
|
+
until cache_cursor == '0'
|
|
216
195
|
end
|
|
217
196
|
|
|
218
197
|
-- Delete any remaining keys
|
|
@@ -229,11 +208,15 @@ _RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = n
|
|
|
229
208
|
return channels
|
|
230
209
|
`;
|
|
231
210
|
try {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
211
|
+
const [activeInstances, cachedInstances] = yield Promise.all([
|
|
212
|
+
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_getActiveInstances).call(this),
|
|
213
|
+
__classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_getCachedInstances).call(this),
|
|
214
|
+
]);
|
|
215
|
+
const deadInstances = cachedInstances.filter((id) => !activeInstances.includes(id));
|
|
216
|
+
if (deadInstances.length === 0) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const affectedChannels = yield __classPrivateFieldGet(this, _RedisClient_redisClient, "f").eval(script, 0, JSON.stringify(deadInstances));
|
|
237
220
|
if (affectedChannels.length > 0) {
|
|
238
221
|
const promises = affectedChannels.map((pair) => {
|
|
239
222
|
const [endpointId, channelId] = pair.split(':');
|
|
@@ -246,80 +229,6 @@ _RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = n
|
|
|
246
229
|
console.error('Error cleaning up disconnected clients:', error);
|
|
247
230
|
}
|
|
248
231
|
});
|
|
249
|
-
}, _RedisClient_getAllInstanceIds = function _RedisClient_getAllInstanceIds() {
|
|
250
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
251
|
-
const script = `
|
|
252
|
-
local instance_ids = {}
|
|
253
|
-
local seen = {} -- For deduplication
|
|
254
|
-
|
|
255
|
-
-- 1. Get instances from distributed_instances set
|
|
256
|
-
local registered = redis.call('SMEMBERS', 'distributed_instances')
|
|
257
|
-
for _, id in ipairs(registered) do
|
|
258
|
-
if not seen[id] then
|
|
259
|
-
seen[id] = true
|
|
260
|
-
table.insert(instance_ids, id)
|
|
261
|
-
end
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
-- 2. Get instances from heartbeat keys
|
|
265
|
-
local cursor = '0'
|
|
266
|
-
repeat
|
|
267
|
-
local result = redis.call('SCAN', cursor, 'MATCH', 'heartbeat:*', 'COUNT', 100)
|
|
268
|
-
cursor = result[1]
|
|
269
|
-
local keys = result[2]
|
|
270
|
-
|
|
271
|
-
for _, key in ipairs(keys) do
|
|
272
|
-
local id = string.match(key, 'heartbeat:([^:]+)')
|
|
273
|
-
if id and not seen[id] then
|
|
274
|
-
seen[id] = true
|
|
275
|
-
table.insert(instance_ids, id)
|
|
276
|
-
end
|
|
277
|
-
end
|
|
278
|
-
until cursor == '0'
|
|
279
|
-
|
|
280
|
-
-- 3. Get instances from metadata keys
|
|
281
|
-
cursor = '0'
|
|
282
|
-
repeat
|
|
283
|
-
local result = redis.call('SCAN', cursor, 'MATCH', 'instance_metadata:*', 'COUNT', 100)
|
|
284
|
-
cursor = result[1]
|
|
285
|
-
local keys = result[2]
|
|
286
|
-
|
|
287
|
-
for _, key in ipairs(keys) do
|
|
288
|
-
local id = string.match(key, 'instance_metadata:([^:]+)')
|
|
289
|
-
if id and not seen[id] then
|
|
290
|
-
seen[id] = true
|
|
291
|
-
table.insert(instance_ids, id)
|
|
292
|
-
end
|
|
293
|
-
end
|
|
294
|
-
until cursor == '0'
|
|
295
|
-
|
|
296
|
-
-- 4. Get instances from cache keys
|
|
297
|
-
cursor = '0'
|
|
298
|
-
repeat
|
|
299
|
-
local result = redis.call('SCAN', cursor, 'MATCH', '*_cache:*', 'COUNT', 100)
|
|
300
|
-
cursor = result[1]
|
|
301
|
-
local keys = result[2]
|
|
302
|
-
|
|
303
|
-
for _, key in ipairs(keys) do
|
|
304
|
-
local id = string.match(key, '_cache:([^:]+)')
|
|
305
|
-
if id and not seen[id] then
|
|
306
|
-
seen[id] = true
|
|
307
|
-
table.insert(instance_ids, id)
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
until cursor == '0'
|
|
311
|
-
|
|
312
|
-
return instance_ids
|
|
313
|
-
`;
|
|
314
|
-
let response = [];
|
|
315
|
-
try {
|
|
316
|
-
response = (yield __classPrivateFieldGet(this, _RedisClient_redisClient, "f").eval(script, 0));
|
|
317
|
-
}
|
|
318
|
-
catch (error) {
|
|
319
|
-
console.error('Error getting all instance IDs:', error);
|
|
320
|
-
}
|
|
321
|
-
return response;
|
|
322
|
-
});
|
|
323
232
|
}, _RedisClient_startPeriodicCleanup = function _RedisClient_startPeriodicCleanup() {
|
|
324
233
|
__classPrivateFieldSet(this, _RedisClient_cleanupTimer, setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
325
234
|
try {
|
|
@@ -332,19 +241,12 @@ _RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = n
|
|
|
332
241
|
}, _RedisClient_startHeartbeat = function _RedisClient_startHeartbeat() {
|
|
333
242
|
__classPrivateFieldSet(this, _RedisClient_heartbeatTimer, setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
334
243
|
try {
|
|
335
|
-
yield __classPrivateFieldGet(this, _RedisClient_instances, "m",
|
|
244
|
+
yield __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_registerInstance).call(this);
|
|
336
245
|
}
|
|
337
246
|
catch (error) {
|
|
338
247
|
console.error('Error performing heartbeat:', error);
|
|
339
248
|
}
|
|
340
249
|
}), __classPrivateFieldGet(this, _RedisClient_heartbeatInterval, "f")), "f");
|
|
341
|
-
}, _RedisClient_performHeartbeat = function _RedisClient_performHeartbeat() {
|
|
342
|
-
const now = Date.now().toString();
|
|
343
|
-
const multi = __classPrivateFieldGet(this, _RedisClient_redisClient, "f").multi();
|
|
344
|
-
multi
|
|
345
|
-
.set(`heartbeat:${__classPrivateFieldGet(this, _RedisClient_instanceId, "f")}`, now, 'EX', __classPrivateFieldGet(this, _RedisClient_instanceTtl, "f"))
|
|
346
|
-
.hset(`instance_metadata:${__classPrivateFieldGet(this, _RedisClient_instanceId, "f")}`, 'last_seen', now);
|
|
347
|
-
return multi.exec();
|
|
348
250
|
}, _RedisClient_unsubscribeFromChannels = function _RedisClient_unsubscribeFromChannels() {
|
|
349
251
|
return __awaiter(this, void 0, void 0, function* () {
|
|
350
252
|
yield __classPrivateFieldGet(this, _RedisClient_subClient, "f").unsubscribe(__classPrivateFieldGet(this, _RedisClient_instances, "a", _RedisClient_presence_changes_channel_get), __classPrivateFieldGet(this, _RedisClient_instances, "a", _RedisClient_assigns_changes_channel_get), __classPrivateFieldGet(this, _RedisClient_instances, "a", _RedisClient_channel_messages_channel_get), __classPrivateFieldGet(this, _RedisClient_instances, "a", _RedisClient_user_leaves_channel_get));
|
|
@@ -404,7 +306,7 @@ _RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = n
|
|
|
404
306
|
}
|
|
405
307
|
});
|
|
406
308
|
}, _RedisClient_subscribeToStateSync = function _RedisClient_subscribeToStateSync(endpoint, channel, callback) {
|
|
407
|
-
const interval = setInterval(() => __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_emitStateSyncEvent).call(this, endpoint, channel), __classPrivateFieldGet(this,
|
|
309
|
+
const interval = setInterval(() => __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_emitStateSyncEvent).call(this, endpoint, channel), __classPrivateFieldGet(this, _RedisClient_stateSyncInterval, "f"));
|
|
408
310
|
const subscription = __classPrivateFieldGet(this, _RedisClient_stateSyncPublisher, "f").subscribe((_a) => {
|
|
409
311
|
var { endpointId, channelId } = _a, data = __rest(_a, ["endpointId", "channelId"]);
|
|
410
312
|
if (endpointId === endpoint && channelId === channel) {
|
|
@@ -463,8 +365,6 @@ _RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = n
|
|
|
463
365
|
|
|
464
366
|
if state ~= '' then
|
|
465
367
|
redis.call('HSET', KEYS[1], userId, state)
|
|
466
|
-
-- Set TTL on cache key
|
|
467
|
-
redis.call('EXPIRE', KEYS[1], ${__classPrivateFieldGet(this, _RedisClient_instanceTtl, "f")})
|
|
468
368
|
else
|
|
469
369
|
redis.call('HDEL', KEYS[1], userId)
|
|
470
370
|
end
|
|
@@ -480,59 +380,107 @@ _RedisClient_heartbeatInterval = new WeakMap(), _RedisClient_cleanupInterval = n
|
|
|
480
380
|
}, _RedisClient_emitStateSyncEvent = function _RedisClient_emitStateSyncEvent(endpointId_1, channelId_1) {
|
|
481
381
|
return __awaiter(this, arguments, void 0, function* (endpointId, channelId, initialFetch = false) {
|
|
482
382
|
const script = `
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
383
|
+
local instances = ARGV[1]
|
|
384
|
+
local presence_data = {}
|
|
385
|
+
local assigns_data = {}
|
|
386
|
+
|
|
387
|
+
-- Parse instance IDs array
|
|
388
|
+
local instance_ids = cjson.decode(instances)
|
|
389
|
+
|
|
390
|
+
for _, instance in ipairs(instance_ids) do
|
|
391
|
+
local presence_key = 'presence_cache:' .. instance .. ':' .. ARGV[2] .. ':' .. ARGV[3]
|
|
392
|
+
local assigns_key = 'assigns_cache:' .. instance .. ':' .. ARGV[2] .. ':' .. ARGV[3]
|
|
393
|
+
|
|
394
|
+
-- Get all presence data for this instance and channel
|
|
395
|
+
local presence = redis.call('HGETALL', presence_key)
|
|
396
|
+
for i = 1, #presence, 2 do
|
|
397
|
+
presence_data[presence[i]] = presence[i + 1]
|
|
492
398
|
end
|
|
493
399
|
|
|
494
|
-
|
|
495
|
-
|
|
400
|
+
-- Get all assigns data for this instance and channel
|
|
401
|
+
local assigns = redis.call('HGETALL', assigns_key)
|
|
402
|
+
for i = 1, #assigns, 2 do
|
|
403
|
+
assigns_data[assigns[i]] = assigns[i + 1]
|
|
404
|
+
end
|
|
496
405
|
end
|
|
497
|
-
|
|
498
|
-
-- Get all registered instances
|
|
499
|
-
local active_instances = redis.call('SMEMBERS', 'distributed_instances')
|
|
500
|
-
local presence_data = {}
|
|
501
|
-
local assigns_data = {}
|
|
502
406
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
407
|
+
return {cjson.encode(presence_data), cjson.encode(assigns_data)}
|
|
408
|
+
`;
|
|
409
|
+
try {
|
|
410
|
+
// Get active instances
|
|
411
|
+
const activeInstances = yield __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_getActiveInstances).call(this);
|
|
412
|
+
// Get the data using our active instances
|
|
413
|
+
const [presenceData, assignsData] = yield __classPrivateFieldGet(this, _RedisClient_redisClient, "f").eval(script, 0, JSON.stringify(activeInstances), endpointId, channelId);
|
|
414
|
+
const event = {
|
|
415
|
+
endpointId,
|
|
416
|
+
channelId,
|
|
417
|
+
initialFetch,
|
|
418
|
+
presence: __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_generateCache).call(this, presenceData),
|
|
419
|
+
assigns: __classPrivateFieldGet(this, _RedisClient_instances, "m", _RedisClient_generateCache).call(this, assignsData),
|
|
420
|
+
};
|
|
421
|
+
__classPrivateFieldGet(this, _RedisClient_stateSyncPublisher, "f").publish(event);
|
|
422
|
+
}
|
|
423
|
+
catch (error) {
|
|
424
|
+
console.error('Error emitting state sync event:', error);
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
}, _RedisClient_getActiveInstances = function _RedisClient_getActiveInstances() {
|
|
428
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
429
|
+
const script = `
|
|
430
|
+
local active_instances = {}
|
|
431
|
+
|
|
432
|
+
local cursor = '0'
|
|
433
|
+
repeat
|
|
434
|
+
local result = redis.call('SCAN', cursor, 'MATCH', 'heartbeat:*', 'COUNT', 100)
|
|
435
|
+
cursor = result[1]
|
|
436
|
+
|
|
437
|
+
for _, key in ipairs(result[2]) do
|
|
438
|
+
local id = string.match(key, 'heartbeat:([^:]+)')
|
|
439
|
+
if id then
|
|
440
|
+
table.insert(active_instances, id)
|
|
516
441
|
end
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
442
|
+
end
|
|
443
|
+
until cursor == '0'
|
|
444
|
+
|
|
445
|
+
return active_instances
|
|
446
|
+
`;
|
|
447
|
+
try {
|
|
448
|
+
return yield __classPrivateFieldGet(this, _RedisClient_redisClient, "f").eval(script, 0);
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
console.error('Error getting active instances:', error);
|
|
452
|
+
return [];
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
}, _RedisClient_getCachedInstances = function _RedisClient_getCachedInstances() {
|
|
456
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
457
|
+
const script = `
|
|
458
|
+
local seen = {}
|
|
459
|
+
local cached_instances = {}
|
|
460
|
+
|
|
461
|
+
local cursor = '0'
|
|
462
|
+
repeat
|
|
463
|
+
local result = redis.call('SCAN', cursor, 'MATCH', '*_cache:*', 'COUNT', 100)
|
|
464
|
+
cursor = result[1]
|
|
465
|
+
|
|
466
|
+
for _, key in ipairs(result[2]) do
|
|
467
|
+
local id = string.match(key, '_cache:([^:]+)')
|
|
468
|
+
if id and not seen[id] then
|
|
469
|
+
seen[id] = true
|
|
470
|
+
table.insert(cached_instances, id)
|
|
521
471
|
end
|
|
522
472
|
end
|
|
523
|
-
|
|
473
|
+
until cursor == '0'
|
|
524
474
|
|
|
525
|
-
return
|
|
475
|
+
return cached_instances
|
|
526
476
|
`;
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
};
|
|
535
|
-
__classPrivateFieldGet(this, _RedisClient_stateSyncPublisher, "f").publish(event);
|
|
477
|
+
try {
|
|
478
|
+
return yield __classPrivateFieldGet(this, _RedisClient_redisClient, "f").eval(script, 0);
|
|
479
|
+
}
|
|
480
|
+
catch (error) {
|
|
481
|
+
console.error('Error getting cached instances:', error);
|
|
482
|
+
return [];
|
|
483
|
+
}
|
|
536
484
|
});
|
|
537
485
|
}, _RedisClient_generateCache = function _RedisClient_generateCache(data) {
|
|
538
486
|
const first = Object.entries(JSON.parse(data));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eleven-am/pondsocket",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.193",
|
|
4
4
|
"description": "PondSocket is a fast simple socket server",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"socket",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"prettier": "^3.5.2",
|
|
61
61
|
"source-map-support": "^0.5.21",
|
|
62
62
|
"supertest": "^7.0.0",
|
|
63
|
-
"ts-jest": "^29.2.
|
|
63
|
+
"ts-jest": "^29.2.6",
|
|
64
64
|
"ts-loader": "^9.5.2",
|
|
65
65
|
"ts-node": "^10.9.2",
|
|
66
66
|
"tsconfig-paths": "^4.2.0",
|