@socket.io/redis-streams-adapter 0.2.0 → 0.2.1
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/README.md +81 -0
- package/dist/adapter.d.ts +2 -13
- package/dist/adapter.js +13 -18
- package/dist/util.d.ts +12 -0
- package/dist/util.js +66 -13
- package/package.json +4 -3
- package/dist/cluster-adapter-v2.d.ts +0 -184
- package/dist/cluster-adapter-v2.js +0 -488
- package/dist/cluster-adapter.d.ts +0 -54
- package/dist/cluster-adapter.js +0 -420
|
@@ -1,488 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ClusterAdapterWithHeartbeat = exports.ClusterAdapter = exports.MessageType = void 0;
|
|
4
|
-
const socket_io_adapter_1 = require("socket.io-adapter");
|
|
5
|
-
const debug_1 = require("debug");
|
|
6
|
-
const crypto_1 = require("crypto");
|
|
7
|
-
const debug = (0, debug_1.default)("socket.io-adapter");
|
|
8
|
-
const EMITTER_UID = "emitter";
|
|
9
|
-
const DEFAULT_TIMEOUT = 5000;
|
|
10
|
-
const randomId = () => (0, crypto_1.randomBytes)(8).toString("hex");
|
|
11
|
-
var MessageType;
|
|
12
|
-
(function (MessageType) {
|
|
13
|
-
MessageType[MessageType["INITIAL_HEARTBEAT"] = 1] = "INITIAL_HEARTBEAT";
|
|
14
|
-
MessageType[MessageType["HEARTBEAT"] = 2] = "HEARTBEAT";
|
|
15
|
-
MessageType[MessageType["BROADCAST"] = 3] = "BROADCAST";
|
|
16
|
-
MessageType[MessageType["SOCKETS_JOIN"] = 4] = "SOCKETS_JOIN";
|
|
17
|
-
MessageType[MessageType["SOCKETS_LEAVE"] = 5] = "SOCKETS_LEAVE";
|
|
18
|
-
MessageType[MessageType["DISCONNECT_SOCKETS"] = 6] = "DISCONNECT_SOCKETS";
|
|
19
|
-
MessageType[MessageType["FETCH_SOCKETS"] = 7] = "FETCH_SOCKETS";
|
|
20
|
-
MessageType[MessageType["FETCH_SOCKETS_RESPONSE"] = 8] = "FETCH_SOCKETS_RESPONSE";
|
|
21
|
-
MessageType[MessageType["SERVER_SIDE_EMIT"] = 9] = "SERVER_SIDE_EMIT";
|
|
22
|
-
MessageType[MessageType["SERVER_SIDE_EMIT_RESPONSE"] = 10] = "SERVER_SIDE_EMIT_RESPONSE";
|
|
23
|
-
MessageType[MessageType["BROADCAST_CLIENT_COUNT"] = 11] = "BROADCAST_CLIENT_COUNT";
|
|
24
|
-
MessageType[MessageType["BROADCAST_ACK"] = 12] = "BROADCAST_ACK";
|
|
25
|
-
})(MessageType = exports.MessageType || (exports.MessageType = {}));
|
|
26
|
-
function encodeOptions(opts) {
|
|
27
|
-
return {
|
|
28
|
-
rooms: [...opts.rooms],
|
|
29
|
-
except: [...opts.except],
|
|
30
|
-
flags: opts.flags,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function decodeOptions(opts) {
|
|
34
|
-
return {
|
|
35
|
-
rooms: new Set(opts.rooms),
|
|
36
|
-
except: new Set(opts.except),
|
|
37
|
-
flags: opts.flags,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* A cluster-ready adapter. Any extending class must:
|
|
42
|
-
*
|
|
43
|
-
* - implement {@link ClusterAdapter#publishMessage} and {@link ClusterAdapter#publishResponse}
|
|
44
|
-
* - call {@link ClusterAdapter#onMessage} and {@link ClusterAdapter#onResponse}
|
|
45
|
-
*/
|
|
46
|
-
class ClusterAdapter extends socket_io_adapter_1.Adapter {
|
|
47
|
-
uid;
|
|
48
|
-
requests = new Map();
|
|
49
|
-
ackRequests = new Map();
|
|
50
|
-
constructor(nsp) {
|
|
51
|
-
super(nsp);
|
|
52
|
-
this.uid = randomId();
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Called when receiving a message from another member of the cluster.
|
|
56
|
-
*
|
|
57
|
-
* @param message
|
|
58
|
-
* @param offset
|
|
59
|
-
* @protected
|
|
60
|
-
*/
|
|
61
|
-
async onMessage(message, offset) {
|
|
62
|
-
if (message.uid === this.uid) {
|
|
63
|
-
debug("ignore message from self");
|
|
64
|
-
}
|
|
65
|
-
debug("new event of type %d from %s", message.type, message.uid);
|
|
66
|
-
switch (message.type) {
|
|
67
|
-
case MessageType.BROADCAST: {
|
|
68
|
-
const withAck = message.data.requestId !== undefined;
|
|
69
|
-
if (withAck) {
|
|
70
|
-
super.broadcastWithAck(message.data.packet, decodeOptions(message.data.opts), (clientCount) => {
|
|
71
|
-
debug("waiting for %d client acknowledgements", clientCount);
|
|
72
|
-
this.publishResponse(message.uid, {
|
|
73
|
-
type: MessageType.BROADCAST_CLIENT_COUNT,
|
|
74
|
-
data: {
|
|
75
|
-
requestId: message.data.requestId,
|
|
76
|
-
clientCount,
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
}, (arg) => {
|
|
80
|
-
debug("received acknowledgement with value %j", arg);
|
|
81
|
-
this.publishResponse(message.uid, {
|
|
82
|
-
type: MessageType.BROADCAST_ACK,
|
|
83
|
-
data: {
|
|
84
|
-
requestId: message.data.requestId,
|
|
85
|
-
packet: arg,
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
const packet = message.data.packet;
|
|
92
|
-
const opts = decodeOptions(message.data.opts);
|
|
93
|
-
this.addOffsetIfNecessary(packet, opts, offset);
|
|
94
|
-
super.broadcast(packet, opts);
|
|
95
|
-
}
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
case MessageType.SOCKETS_JOIN:
|
|
99
|
-
super.addSockets(decodeOptions(message.data.opts), message.data.rooms);
|
|
100
|
-
break;
|
|
101
|
-
case MessageType.SOCKETS_LEAVE:
|
|
102
|
-
super.delSockets(decodeOptions(message.data.opts), message.data.rooms);
|
|
103
|
-
break;
|
|
104
|
-
case MessageType.DISCONNECT_SOCKETS:
|
|
105
|
-
super.disconnectSockets(decodeOptions(message.data.opts), message.data.close);
|
|
106
|
-
break;
|
|
107
|
-
case MessageType.FETCH_SOCKETS: {
|
|
108
|
-
debug("calling fetchSockets with opts %j", message.data.opts);
|
|
109
|
-
const localSockets = await super.fetchSockets(decodeOptions(message.data.opts));
|
|
110
|
-
this.publishResponse(message.uid, {
|
|
111
|
-
type: MessageType.FETCH_SOCKETS_RESPONSE,
|
|
112
|
-
data: {
|
|
113
|
-
requestId: message.data.requestId,
|
|
114
|
-
sockets: localSockets.map((socket) => {
|
|
115
|
-
// remove sessionStore from handshake, as it may contain circular references
|
|
116
|
-
const { sessionStore, ...handshake } = socket.handshake;
|
|
117
|
-
return {
|
|
118
|
-
id: socket.id,
|
|
119
|
-
handshake,
|
|
120
|
-
rooms: [...socket.rooms],
|
|
121
|
-
data: socket.data,
|
|
122
|
-
};
|
|
123
|
-
}),
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
case MessageType.SERVER_SIDE_EMIT: {
|
|
129
|
-
const packet = message.data.packet;
|
|
130
|
-
const withAck = message.data.requestId !== undefined;
|
|
131
|
-
if (!withAck) {
|
|
132
|
-
this.nsp._onServerSideEmit(packet);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
let called = false;
|
|
136
|
-
const callback = (arg) => {
|
|
137
|
-
// only one argument is expected
|
|
138
|
-
if (called) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
called = true;
|
|
142
|
-
debug("calling acknowledgement with %j", arg);
|
|
143
|
-
this.publishResponse(message.uid, {
|
|
144
|
-
type: MessageType.SERVER_SIDE_EMIT_RESPONSE,
|
|
145
|
-
data: {
|
|
146
|
-
requestId: message.data.requestId,
|
|
147
|
-
packet: arg,
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
};
|
|
151
|
-
packet.push(callback);
|
|
152
|
-
this.nsp._onServerSideEmit(packet);
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
// @ts-ignore
|
|
156
|
-
case MessageType.BROADCAST_CLIENT_COUNT:
|
|
157
|
-
// @ts-ignore
|
|
158
|
-
case MessageType.BROADCAST_ACK:
|
|
159
|
-
// @ts-ignore
|
|
160
|
-
case MessageType.FETCH_SOCKETS_RESPONSE:
|
|
161
|
-
// @ts-ignore
|
|
162
|
-
case MessageType.SERVER_SIDE_EMIT_RESPONSE:
|
|
163
|
-
this.onResponse(message);
|
|
164
|
-
break;
|
|
165
|
-
default:
|
|
166
|
-
debug("unknown message type: %s", message.type);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Called when receiving a response from another member of the cluster.
|
|
171
|
-
*
|
|
172
|
-
* @param response
|
|
173
|
-
* @protected
|
|
174
|
-
*/
|
|
175
|
-
onResponse(response) {
|
|
176
|
-
const requestId = response.data.requestId;
|
|
177
|
-
debug("received response %s to request %s", response.type, requestId);
|
|
178
|
-
switch (response.type) {
|
|
179
|
-
case MessageType.BROADCAST_CLIENT_COUNT: {
|
|
180
|
-
this.ackRequests
|
|
181
|
-
.get(requestId)
|
|
182
|
-
?.clientCountCallback(response.data.clientCount);
|
|
183
|
-
break;
|
|
184
|
-
}
|
|
185
|
-
case MessageType.BROADCAST_ACK: {
|
|
186
|
-
this.ackRequests.get(requestId)?.ack(response.data.packet);
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
case MessageType.FETCH_SOCKETS_RESPONSE: {
|
|
190
|
-
const request = this.requests.get(requestId);
|
|
191
|
-
if (!request) {
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
request.current++;
|
|
195
|
-
response.data.sockets.forEach((socket) => request.responses.push(socket));
|
|
196
|
-
if (request.current === request.expected) {
|
|
197
|
-
clearTimeout(request.timeout);
|
|
198
|
-
request.resolve(request.responses);
|
|
199
|
-
this.requests.delete(requestId);
|
|
200
|
-
}
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
case MessageType.SERVER_SIDE_EMIT_RESPONSE: {
|
|
204
|
-
const request = this.requests.get(requestId);
|
|
205
|
-
if (!request) {
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
request.current++;
|
|
209
|
-
request.responses.push(response.data.packet);
|
|
210
|
-
if (request.current === request.expected) {
|
|
211
|
-
clearTimeout(request.timeout);
|
|
212
|
-
request.resolve(null, request.responses);
|
|
213
|
-
this.requests.delete(requestId);
|
|
214
|
-
}
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
default:
|
|
218
|
-
// @ts-ignore
|
|
219
|
-
debug("unknown response type: %s", response.type);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
async broadcast(packet, opts) {
|
|
223
|
-
const onlyLocal = opts.flags?.local;
|
|
224
|
-
if (!onlyLocal) {
|
|
225
|
-
try {
|
|
226
|
-
const offset = await this.publish({
|
|
227
|
-
type: MessageType.BROADCAST,
|
|
228
|
-
data: {
|
|
229
|
-
packet,
|
|
230
|
-
opts: encodeOptions(opts),
|
|
231
|
-
},
|
|
232
|
-
});
|
|
233
|
-
this.addOffsetIfNecessary(packet, opts, offset);
|
|
234
|
-
}
|
|
235
|
-
catch (e) {
|
|
236
|
-
return debug("error while broadcasting message: %s", e.message);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
super.broadcast(packet, opts);
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Adds an offset at the end of the data array in order to allow the client to receive any missed packets when it
|
|
243
|
-
* reconnects after a temporary disconnection.
|
|
244
|
-
*
|
|
245
|
-
* @param packet
|
|
246
|
-
* @param opts
|
|
247
|
-
* @param offset
|
|
248
|
-
* @private
|
|
249
|
-
*/
|
|
250
|
-
addOffsetIfNecessary(packet, opts, offset) {
|
|
251
|
-
if (!this.nsp.server.opts.connectionStateRecovery) {
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
const isEventPacket = packet.type === 2;
|
|
255
|
-
// packets with acknowledgement are not stored because the acknowledgement function cannot be serialized and
|
|
256
|
-
// restored on another server upon reconnection
|
|
257
|
-
const withoutAcknowledgement = packet.id === undefined;
|
|
258
|
-
const notVolatile = opts.flags?.volatile === undefined;
|
|
259
|
-
if (isEventPacket && withoutAcknowledgement && notVolatile) {
|
|
260
|
-
packet.data.push(offset);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
broadcastWithAck(packet, opts, clientCountCallback, ack) {
|
|
264
|
-
const onlyLocal = opts?.flags?.local;
|
|
265
|
-
if (!onlyLocal) {
|
|
266
|
-
const requestId = randomId();
|
|
267
|
-
this.publish({
|
|
268
|
-
type: MessageType.BROADCAST,
|
|
269
|
-
data: {
|
|
270
|
-
packet,
|
|
271
|
-
requestId,
|
|
272
|
-
opts: encodeOptions(opts),
|
|
273
|
-
},
|
|
274
|
-
});
|
|
275
|
-
this.ackRequests.set(requestId, {
|
|
276
|
-
clientCountCallback,
|
|
277
|
-
ack,
|
|
278
|
-
});
|
|
279
|
-
// we have no way to know at this level whether the server has received an acknowledgement from each client, so we
|
|
280
|
-
// will simply clean up the ackRequests map after the given delay
|
|
281
|
-
setTimeout(() => {
|
|
282
|
-
this.ackRequests.delete(requestId);
|
|
283
|
-
}, opts.flags.timeout);
|
|
284
|
-
}
|
|
285
|
-
super.broadcastWithAck(packet, opts, clientCountCallback, ack);
|
|
286
|
-
}
|
|
287
|
-
addSockets(opts, rooms) {
|
|
288
|
-
super.addSockets(opts, rooms);
|
|
289
|
-
const onlyLocal = opts.flags?.local;
|
|
290
|
-
if (onlyLocal) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
this.publish({
|
|
294
|
-
type: MessageType.SOCKETS_JOIN,
|
|
295
|
-
data: {
|
|
296
|
-
opts: encodeOptions(opts),
|
|
297
|
-
rooms,
|
|
298
|
-
},
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
delSockets(opts, rooms) {
|
|
302
|
-
super.delSockets(opts, rooms);
|
|
303
|
-
const onlyLocal = opts.flags?.local;
|
|
304
|
-
if (onlyLocal) {
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
this.publish({
|
|
308
|
-
type: MessageType.SOCKETS_LEAVE,
|
|
309
|
-
data: {
|
|
310
|
-
opts: encodeOptions(opts),
|
|
311
|
-
rooms,
|
|
312
|
-
},
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
disconnectSockets(opts, close) {
|
|
316
|
-
super.disconnectSockets(opts, close);
|
|
317
|
-
const onlyLocal = opts.flags?.local;
|
|
318
|
-
if (onlyLocal) {
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
this.publish({
|
|
322
|
-
type: MessageType.DISCONNECT_SOCKETS,
|
|
323
|
-
data: {
|
|
324
|
-
opts: encodeOptions(opts),
|
|
325
|
-
close,
|
|
326
|
-
},
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
async fetchSockets(opts) {
|
|
330
|
-
const [localSockets, serverCount] = await Promise.all([
|
|
331
|
-
super.fetchSockets(opts),
|
|
332
|
-
this.serverCount(),
|
|
333
|
-
]);
|
|
334
|
-
const expectedResponseCount = serverCount - 1;
|
|
335
|
-
if (opts.flags?.local || expectedResponseCount === 0) {
|
|
336
|
-
return localSockets;
|
|
337
|
-
}
|
|
338
|
-
const requestId = randomId();
|
|
339
|
-
return new Promise((resolve, reject) => {
|
|
340
|
-
const timeout = setTimeout(() => {
|
|
341
|
-
const storedRequest = this.requests.get(requestId);
|
|
342
|
-
if (storedRequest) {
|
|
343
|
-
reject(new Error(`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`));
|
|
344
|
-
this.requests.delete(requestId);
|
|
345
|
-
}
|
|
346
|
-
}, opts.flags.timeout || DEFAULT_TIMEOUT);
|
|
347
|
-
const storedRequest = {
|
|
348
|
-
type: MessageType.FETCH_SOCKETS,
|
|
349
|
-
resolve,
|
|
350
|
-
timeout,
|
|
351
|
-
current: 0,
|
|
352
|
-
expected: expectedResponseCount,
|
|
353
|
-
responses: localSockets,
|
|
354
|
-
};
|
|
355
|
-
this.requests.set(requestId, storedRequest);
|
|
356
|
-
this.publish({
|
|
357
|
-
type: MessageType.FETCH_SOCKETS,
|
|
358
|
-
data: {
|
|
359
|
-
opts: encodeOptions(opts),
|
|
360
|
-
requestId,
|
|
361
|
-
},
|
|
362
|
-
});
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
async serverSideEmit(packet) {
|
|
366
|
-
const withAck = typeof packet[packet.length - 1] === "function";
|
|
367
|
-
if (!withAck) {
|
|
368
|
-
return this.publish({
|
|
369
|
-
type: MessageType.SERVER_SIDE_EMIT,
|
|
370
|
-
data: {
|
|
371
|
-
packet,
|
|
372
|
-
},
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
const ack = packet.pop();
|
|
376
|
-
const expectedResponseCount = (await this.serverCount()) - 1;
|
|
377
|
-
debug('waiting for %d responses to "serverSideEmit" request', expectedResponseCount);
|
|
378
|
-
if (expectedResponseCount <= 0) {
|
|
379
|
-
return ack(null, []);
|
|
380
|
-
}
|
|
381
|
-
const requestId = randomId();
|
|
382
|
-
const timeout = setTimeout(() => {
|
|
383
|
-
const storedRequest = this.requests.get(requestId);
|
|
384
|
-
if (storedRequest) {
|
|
385
|
-
ack(new Error(`timeout reached: only ${storedRequest.current} responses received out of ${storedRequest.expected}`), storedRequest.responses);
|
|
386
|
-
this.requests.delete(requestId);
|
|
387
|
-
}
|
|
388
|
-
}, DEFAULT_TIMEOUT);
|
|
389
|
-
const storedRequest = {
|
|
390
|
-
type: MessageType.SERVER_SIDE_EMIT,
|
|
391
|
-
resolve: ack,
|
|
392
|
-
timeout,
|
|
393
|
-
current: 0,
|
|
394
|
-
expected: expectedResponseCount,
|
|
395
|
-
responses: [],
|
|
396
|
-
};
|
|
397
|
-
this.requests.set(requestId, storedRequest);
|
|
398
|
-
this.publish({
|
|
399
|
-
type: MessageType.SERVER_SIDE_EMIT,
|
|
400
|
-
data: {
|
|
401
|
-
requestId,
|
|
402
|
-
packet,
|
|
403
|
-
},
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
publish(message) {
|
|
407
|
-
return this.publishMessage({
|
|
408
|
-
uid: this.uid,
|
|
409
|
-
nsp: this.nsp.name,
|
|
410
|
-
...message,
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
publishResponse(requesterUid, message) {
|
|
414
|
-
const response = message;
|
|
415
|
-
response.uid = this.uid;
|
|
416
|
-
response.nsp = this.nsp.name;
|
|
417
|
-
return this.doPublishResponse(requesterUid, response);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
exports.ClusterAdapter = ClusterAdapter;
|
|
421
|
-
class ClusterAdapterWithHeartbeat extends ClusterAdapter {
|
|
422
|
-
_opts;
|
|
423
|
-
heartbeatTimer;
|
|
424
|
-
nodesMap = new Map(); // uid => timestamp of last message
|
|
425
|
-
constructor(nsp, opts) {
|
|
426
|
-
super(nsp);
|
|
427
|
-
this._opts = Object.assign({
|
|
428
|
-
heartbeatInterval: 5000,
|
|
429
|
-
heartbeatTimeout: 10000,
|
|
430
|
-
}, opts);
|
|
431
|
-
}
|
|
432
|
-
init() {
|
|
433
|
-
this.publish({
|
|
434
|
-
type: MessageType.INITIAL_HEARTBEAT,
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
scheduleHeartbeat() {
|
|
438
|
-
if (this.heartbeatTimer) {
|
|
439
|
-
clearTimeout(this.heartbeatTimer);
|
|
440
|
-
}
|
|
441
|
-
this.heartbeatTimer = setTimeout(() => {
|
|
442
|
-
this.publish({
|
|
443
|
-
type: MessageType.HEARTBEAT,
|
|
444
|
-
});
|
|
445
|
-
}, this._opts.heartbeatInterval);
|
|
446
|
-
}
|
|
447
|
-
close() {
|
|
448
|
-
if (this.heartbeatTimer)
|
|
449
|
-
clearTimeout(this.heartbeatTimer);
|
|
450
|
-
}
|
|
451
|
-
async onMessage(message, offset) {
|
|
452
|
-
if (message.uid === this.uid) {
|
|
453
|
-
return debug("ignore message from self");
|
|
454
|
-
}
|
|
455
|
-
if (message.uid && message.uid !== EMITTER_UID) {
|
|
456
|
-
// we track the UID of each sender, in order to know how many servers there are in the cluster
|
|
457
|
-
this.nodesMap.set(message.uid, Date.now());
|
|
458
|
-
}
|
|
459
|
-
switch (message.type) {
|
|
460
|
-
case MessageType.INITIAL_HEARTBEAT:
|
|
461
|
-
this.publish({
|
|
462
|
-
type: MessageType.HEARTBEAT,
|
|
463
|
-
});
|
|
464
|
-
break;
|
|
465
|
-
case MessageType.HEARTBEAT:
|
|
466
|
-
// nothing to do
|
|
467
|
-
break;
|
|
468
|
-
default:
|
|
469
|
-
return super.onMessage(message, offset);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
serverCount() {
|
|
473
|
-
const now = Date.now();
|
|
474
|
-
this.nodesMap.forEach((lastSeen, uid) => {
|
|
475
|
-
const nodeSeemsDown = now - lastSeen > this._opts.heartbeatTimeout;
|
|
476
|
-
if (nodeSeemsDown) {
|
|
477
|
-
debug("node %s seems down", uid);
|
|
478
|
-
this.nodesMap.delete(uid);
|
|
479
|
-
}
|
|
480
|
-
});
|
|
481
|
-
return Promise.resolve(1 + this.nodesMap.size);
|
|
482
|
-
}
|
|
483
|
-
publish(message) {
|
|
484
|
-
this.scheduleHeartbeat();
|
|
485
|
-
return super.publish(message);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
exports.ClusterAdapterWithHeartbeat = ClusterAdapterWithHeartbeat;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { Adapter, BroadcastOptions, Room } from "socket.io-adapter";
|
|
2
|
-
export interface ClusterAdapterOptions {
|
|
3
|
-
/**
|
|
4
|
-
* The number of ms between two heartbeats.
|
|
5
|
-
* @default 5_000
|
|
6
|
-
*/
|
|
7
|
-
heartbeatInterval?: number;
|
|
8
|
-
/**
|
|
9
|
-
* The number of ms without heartbeat before we consider a node down.
|
|
10
|
-
* @default 10_000
|
|
11
|
-
*/
|
|
12
|
-
heartbeatTimeout?: number;
|
|
13
|
-
}
|
|
14
|
-
export declare enum MessageType {
|
|
15
|
-
INITIAL_HEARTBEAT = 1,
|
|
16
|
-
HEARTBEAT = 2,
|
|
17
|
-
BROADCAST = 3,
|
|
18
|
-
SOCKETS_JOIN = 4,
|
|
19
|
-
SOCKETS_LEAVE = 5,
|
|
20
|
-
DISCONNECT_SOCKETS = 6,
|
|
21
|
-
FETCH_SOCKETS = 7,
|
|
22
|
-
FETCH_SOCKETS_RESPONSE = 8,
|
|
23
|
-
SERVER_SIDE_EMIT = 9,
|
|
24
|
-
SERVER_SIDE_EMIT_RESPONSE = 10,
|
|
25
|
-
BROADCAST_CLIENT_COUNT = 11,
|
|
26
|
-
BROADCAST_ACK = 12
|
|
27
|
-
}
|
|
28
|
-
export interface ClusterMessage {
|
|
29
|
-
uid: string;
|
|
30
|
-
nsp: string;
|
|
31
|
-
type: MessageType;
|
|
32
|
-
data?: Record<string, unknown>;
|
|
33
|
-
}
|
|
34
|
-
export declare abstract class ClusterAdapter extends Adapter {
|
|
35
|
-
#private;
|
|
36
|
-
protected constructor(nsp: any, opts: Required<ClusterAdapterOptions>);
|
|
37
|
-
protected initHeartbeat(): void;
|
|
38
|
-
close(): Promise<void> | void;
|
|
39
|
-
onMessage(message: ClusterMessage, offset: string): Promise<any>;
|
|
40
|
-
broadcast(packet: any, opts: BroadcastOptions): Promise<any>;
|
|
41
|
-
broadcastWithAck(packet: any, opts: BroadcastOptions, clientCountCallback: (clientCount: number) => void, ack: (...args: any[]) => void): void;
|
|
42
|
-
serverCount(): Promise<number>;
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
45
|
-
* @param opts
|
|
46
|
-
* @param rooms
|
|
47
|
-
*/
|
|
48
|
-
addSockets(opts: BroadcastOptions, rooms: Room[]): void;
|
|
49
|
-
delSockets(opts: BroadcastOptions, rooms: Room[]): void;
|
|
50
|
-
disconnectSockets(opts: BroadcastOptions, close: boolean): void;
|
|
51
|
-
fetchSockets(opts: BroadcastOptions): Promise<any[]>;
|
|
52
|
-
serverSideEmit(packet: any[]): any;
|
|
53
|
-
abstract doPublish(message: ClusterMessage): Promise<string>;
|
|
54
|
-
}
|