stelar-time-real 3.3.0 → 3.3.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/package.json +1 -1
- package/src/client.d.ts +10 -3
- package/src/client.d.ts.map +1 -1
- package/src/client.js +105 -58
- package/src/client.ts +92 -42
- package/src/index.d.ts +8 -6
- package/src/index.d.ts.map +1 -1
- package/src/index.js +161 -105
- package/src/index.ts +127 -79
- package/src/logger.d.ts +0 -1
- package/src/logger.d.ts.map +1 -1
- package/src/logger.js +5 -8
- package/src/logger.ts +6 -10
- package/src/protocol.d.ts +5 -5
- package/src/protocol.d.ts.map +1 -1
- package/src/protocol.js +39 -25
- package/src/protocol.ts +31 -41
- package/src/websocket.d.ts +14 -8
- package/src/websocket.d.ts.map +1 -1
- package/src/websocket.js +81 -32
- package/src/websocket.ts +68 -30
package/src/index.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @stelar-time-real Server — Dual-protocol: WebSocket (RFC 6455) + binary TCP
|
|
3
|
-
*/
|
|
1
|
+
/** @stelar-time-real Server — Dual-protocol: WebSocket (RFC 6455) + binary TCP */
|
|
4
2
|
import { IncomingMessage, Server as HttpServer, ServerResponse } from 'http';
|
|
5
3
|
import { Socket as NetSocket } from 'net';
|
|
6
4
|
import { TlsOptions } from 'tls';
|
|
@@ -113,6 +111,7 @@ export interface StelarOptions {
|
|
|
113
111
|
eventRateLimits?: EventRateLimits;
|
|
114
112
|
hooks?: StelarHooks;
|
|
115
113
|
customHealthHandler?: (req: IncomingMessage, res: ServerResponse, stats: StelarStats) => void;
|
|
114
|
+
compression?: boolean;
|
|
116
115
|
}
|
|
117
116
|
export interface StelarClientInfo {
|
|
118
117
|
id: string;
|
|
@@ -200,12 +199,12 @@ declare class StelarServer {
|
|
|
200
199
|
private hooks;
|
|
201
200
|
private evRateLimits;
|
|
202
201
|
private clientRates;
|
|
202
|
+
private doCompress;
|
|
203
203
|
private clients;
|
|
204
204
|
private byId;
|
|
205
205
|
private rooms;
|
|
206
206
|
private events;
|
|
207
207
|
private mw;
|
|
208
|
-
private _hb;
|
|
209
208
|
private _rc;
|
|
210
209
|
private _wild;
|
|
211
210
|
private _connH;
|
|
@@ -247,6 +246,7 @@ declare class StelarServer {
|
|
|
247
246
|
heartbeatTimeout: number;
|
|
248
247
|
connectTimeout: number;
|
|
249
248
|
shutdownTimeout: number;
|
|
249
|
+
compression: boolean;
|
|
250
250
|
hasCustomRateLimiter: boolean;
|
|
251
251
|
hasCustomIPTracker: boolean;
|
|
252
252
|
hasCustomClientIdGenerator: boolean;
|
|
@@ -274,11 +274,14 @@ declare class StelarServer {
|
|
|
274
274
|
getPort(): number;
|
|
275
275
|
getStats(): StelarStats;
|
|
276
276
|
onShutdown(cb: (sig: string, force: boolean) => void): this;
|
|
277
|
-
private _sendJson;
|
|
278
277
|
private _write;
|
|
278
|
+
private _sendJson;
|
|
279
279
|
private _sendBin;
|
|
280
|
+
private _flushQueue;
|
|
280
281
|
private _checkRate;
|
|
281
282
|
private _getIP;
|
|
283
|
+
private _startClientHB;
|
|
284
|
+
private _stopClientHB;
|
|
282
285
|
private _register;
|
|
283
286
|
private _unregister;
|
|
284
287
|
private _joinRoom;
|
|
@@ -286,7 +289,6 @@ declare class StelarServer {
|
|
|
286
289
|
private _buildCtx;
|
|
287
290
|
private _runMw;
|
|
288
291
|
private _dispatch;
|
|
289
|
-
private _startHeartbeat;
|
|
290
292
|
private _wsUpgrade;
|
|
291
293
|
private _processWS;
|
|
292
294
|
private _handleWSFrame;
|
package/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
|
package/src/index.js
CHANGED
|
@@ -1,13 +1,35 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @stelar-time-real Server — Dual-protocol: WebSocket (RFC 6455) + binary TCP
|
|
3
|
-
*/
|
|
1
|
+
/** @stelar-time-real Server — Dual-protocol: WebSocket (RFC 6455) + binary TCP */
|
|
4
2
|
import { createServer as createHttp } from 'http';
|
|
5
3
|
import { createServer as createTcp } from 'net';
|
|
6
4
|
import { randomUUID } from 'crypto';
|
|
7
5
|
import { createServer as createTls } from 'tls';
|
|
8
|
-
import { FrameParser, encodeJsonFrame, encodeBinaryFrame, encodePingFrame, encodePongFrame, encodeAckResFrame, encodeConnectFrame, encodeDisconnectFrame, encodeErrorFrame, FRAME_JSON, FRAME_BINARY, FRAME_PING, FRAME_PONG, FRAME_ACK_REQ,
|
|
9
|
-
import { WSFrameParser, buildUpgradeResponse, validateWSKey, createWSTextFrame, createWSBinaryFrame, createWSCloseFrame, createWSPingFrame, createWSPongFrame, OP_TEXT, OP_BINARY, OP_CLOSE, OP_PING, OP_PONG, WebSocketError, CLOSE_POLICY_VIOLATION, CLOSE_MESSAGE_TOO_BIG, CLOSE_GOING_AWAY, DEFAULT_MAX_WS_FRAME_SIZE, } from './websocket.js';
|
|
6
|
+
import { FrameParser, encodeJsonFrame, encodeBinaryFrame, encodePingFrame, encodePongFrame, encodeAckResFrame, encodeConnectFrame, encodeDisconnectFrame, encodeErrorFrame, FRAME_JSON, FRAME_BINARY, FRAME_PING, FRAME_PONG, FRAME_ACK_REQ, FRAME_JOIN, FRAME_LEAVE, FRAME_CONNECT, ProtocolError, DEFAULT_MAX_FRAME_SIZE, } from './protocol.js';
|
|
7
|
+
import { WSFrameParser, buildUpgradeResponse, validateWSKey, createWSTextFrame, createWSBinaryFrame, createWSCloseFrame, createWSPingFrame, createWSPongFrame, OP_TEXT, OP_BINARY, OP_CLOSE, OP_PING, OP_PONG, WebSocketError, CLOSE_POLICY_VIOLATION, CLOSE_MESSAGE_TOO_BIG, CLOSE_GOING_AWAY, DEFAULT_MAX_WS_FRAME_SIZE, clientWantsCompression, } from './websocket.js';
|
|
10
8
|
import { Logger, NULL_LOGGER } from './logger.js';
|
|
9
|
+
/** WS binary framing: [4B headerLen BE][header JSON][binary payload] — length-prefixed, not null-delimited */
|
|
10
|
+
function encodeWSBinary(event, data) {
|
|
11
|
+
const hdr = Buffer.from(JSON.stringify({ event, _binary: true }), 'utf8');
|
|
12
|
+
const payload = Buffer.from(data);
|
|
13
|
+
const frame = Buffer.alloc(4 + hdr.length + payload.length);
|
|
14
|
+
frame.writeUInt32BE(hdr.length, 0);
|
|
15
|
+
hdr.copy(frame, 4);
|
|
16
|
+
payload.copy(frame, 4 + hdr.length);
|
|
17
|
+
return frame;
|
|
18
|
+
}
|
|
19
|
+
function parseWSBinary(payload) {
|
|
20
|
+
if (payload.length < 4)
|
|
21
|
+
return null;
|
|
22
|
+
const hdrLen = payload.readUInt32BE(0);
|
|
23
|
+
if (hdrLen > payload.length - 4)
|
|
24
|
+
return null;
|
|
25
|
+
try {
|
|
26
|
+
const hdr = JSON.parse(payload.subarray(4, 4 + hdrLen).toString('utf8'));
|
|
27
|
+
return { event: hdr.event, buffer: payload.subarray(4 + hdrLen) };
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
11
33
|
class RateLimiter {
|
|
12
34
|
constructor(maxPts = 100, winMs = 1000) {
|
|
13
35
|
this.maxPts = maxPts;
|
|
@@ -57,7 +79,6 @@ class StelarServer {
|
|
|
57
79
|
this.rooms = new Map();
|
|
58
80
|
this.events = new Map();
|
|
59
81
|
this.mw = [];
|
|
60
|
-
this._hb = null;
|
|
61
82
|
this._rc = null;
|
|
62
83
|
this._wild = null;
|
|
63
84
|
this._connH = null;
|
|
@@ -96,6 +117,7 @@ class StelarServer {
|
|
|
96
117
|
this._genId = o.generateClientId || null;
|
|
97
118
|
this._healthFn = o.customHealthHandler || null;
|
|
98
119
|
this.hooks = o.hooks || {};
|
|
120
|
+
this.doCompress = o.compression || false;
|
|
99
121
|
if (o.eventRateLimits)
|
|
100
122
|
for (const [ev, c] of Object.entries(o.eventRateLimits))
|
|
101
123
|
this.evRateLimits.set(ev, new RateLimiter(c.maxPoints, c.windowMs));
|
|
@@ -123,6 +145,8 @@ class StelarServer {
|
|
|
123
145
|
this.hbTimeout = o.heartbeatTimeout;
|
|
124
146
|
if (o.allowedOrigins !== undefined)
|
|
125
147
|
this.origins = o.allowedOrigins;
|
|
148
|
+
if (o.compression !== undefined)
|
|
149
|
+
this.doCompress = o.compression;
|
|
126
150
|
if (o.rateLimit === false) {
|
|
127
151
|
this.rateLimiter = null;
|
|
128
152
|
this._crl = null;
|
|
@@ -158,7 +182,8 @@ class StelarServer {
|
|
|
158
182
|
maxConnections: this.maxConns, maxConnectionsPerIP: this._cit ? -1 : 50,
|
|
159
183
|
maxRooms: this.maxRooms, maxRoomsPerClient: this.maxRoomsPerClient, maxPayloadSize: this.maxPayload,
|
|
160
184
|
heartbeatInterval: this.hbInterval, heartbeatTimeout: this.hbTimeout, connectTimeout: this.connTimeout,
|
|
161
|
-
shutdownTimeout: this.shutdownMs,
|
|
185
|
+
shutdownTimeout: this.shutdownMs, compression: this.doCompress,
|
|
186
|
+
hasCustomRateLimiter: this._crl !== null, hasCustomIPTracker: this._cit !== null,
|
|
162
187
|
hasCustomClientIdGenerator: this._genId !== null, hasCustomHealthHandler: this._healthFn !== null,
|
|
163
188
|
eventRateLimits: Array.from(this.evRateLimits.keys()), hooks: Object.keys(this.hooks), allowedOrigins: this.origins,
|
|
164
189
|
});
|
|
@@ -174,28 +199,35 @@ class StelarServer {
|
|
|
174
199
|
broadcast(event, data, excludeId) {
|
|
175
200
|
if (this.hooks.onBeforeBroadcast?.({ event, data, excludeId }) === false)
|
|
176
201
|
return this;
|
|
177
|
-
const
|
|
202
|
+
const json = JSON.stringify({ event, data });
|
|
203
|
+
const wsF = createWSTextFrame(json);
|
|
204
|
+
const wsFC = this.doCompress ? createWSTextFrame(json, true) : wsF;
|
|
178
205
|
const tcpF = encodeJsonFrame(event, data, this.maxFrame);
|
|
179
206
|
let sent = 0;
|
|
180
207
|
this.clients.forEach(r => { if (excludeId && r.info.id === excludeId)
|
|
181
|
-
return; if (this._write(r, wsF, tcpF))
|
|
208
|
+
return; if (this._write(r, r.compress ? wsFC : wsF, tcpF))
|
|
182
209
|
sent++; });
|
|
183
210
|
this._totalSent += sent;
|
|
184
211
|
return this;
|
|
185
212
|
}
|
|
186
|
-
broadcastBinary(event, buf) {
|
|
213
|
+
broadcastBinary(event, buf) {
|
|
214
|
+
const safeCopy = Buffer.from(new Uint8Array(buf));
|
|
215
|
+
this.clients.forEach(r => this._sendBin(r, event, safeCopy));
|
|
216
|
+
}
|
|
187
217
|
to(room, event, data, excludeId) {
|
|
188
218
|
const ids = this.rooms.get(room);
|
|
189
219
|
if (!ids)
|
|
190
220
|
return this;
|
|
191
|
-
const
|
|
221
|
+
const json = JSON.stringify({ event, data });
|
|
222
|
+
const wsF = createWSTextFrame(json);
|
|
223
|
+
const wsFC = this.doCompress ? createWSTextFrame(json, true) : wsF;
|
|
192
224
|
const tcpF = encodeJsonFrame(event, data, this.maxFrame);
|
|
193
225
|
let sent = 0;
|
|
194
226
|
for (const id of ids) {
|
|
195
227
|
if (excludeId && id === excludeId)
|
|
196
228
|
continue;
|
|
197
229
|
const r = this.byId.get(id);
|
|
198
|
-
if (r && this._write(r, wsF, tcpF))
|
|
230
|
+
if (r && this._write(r, r.compress ? wsFC : wsF, tcpF))
|
|
199
231
|
sent++;
|
|
200
232
|
}
|
|
201
233
|
this._totalSent += sent;
|
|
@@ -228,12 +260,18 @@ class StelarServer {
|
|
|
228
260
|
};
|
|
229
261
|
}
|
|
230
262
|
onShutdown(cb) { this._shutdownCbs.push(cb); return this; }
|
|
231
|
-
/* ── Private:
|
|
232
|
-
|
|
263
|
+
/* ── Private: backpressure-aware write ── */
|
|
264
|
+
_write(r, wsF, tcpF) {
|
|
233
265
|
if (r.socket.destroyed || r.socket.writableEnded)
|
|
234
266
|
return false;
|
|
267
|
+
if (r._writePaused) {
|
|
268
|
+
r._writeQueue.push(r.protocol === 'ws' ? wsF : tcpF);
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
235
271
|
try {
|
|
236
|
-
r.socket.write(r.protocol === 'ws' ?
|
|
272
|
+
const ok = r.socket.write(r.protocol === 'ws' ? wsF : tcpF);
|
|
273
|
+
if (!ok)
|
|
274
|
+
r._writePaused = true;
|
|
237
275
|
r.info.messagesSent++;
|
|
238
276
|
return true;
|
|
239
277
|
}
|
|
@@ -241,11 +279,19 @@ class StelarServer {
|
|
|
241
279
|
return false;
|
|
242
280
|
}
|
|
243
281
|
}
|
|
244
|
-
|
|
282
|
+
_sendJson(r, event, data) {
|
|
245
283
|
if (r.socket.destroyed || r.socket.writableEnded)
|
|
246
284
|
return false;
|
|
247
285
|
try {
|
|
248
|
-
r.
|
|
286
|
+
const frame = r.protocol === 'ws' ? createWSTextFrame(JSON.stringify({ event, data }), r.compress) : encodeJsonFrame(event, data, this.maxFrame);
|
|
287
|
+
if (r._writePaused) {
|
|
288
|
+
r._writeQueue.push(frame);
|
|
289
|
+
r.info.messagesSent++;
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
const ok = r.socket.write(frame);
|
|
293
|
+
if (!ok)
|
|
294
|
+
r._writePaused = true;
|
|
249
295
|
r.info.messagesSent++;
|
|
250
296
|
return true;
|
|
251
297
|
}
|
|
@@ -258,15 +304,26 @@ class StelarServer {
|
|
|
258
304
|
return false;
|
|
259
305
|
try {
|
|
260
306
|
if (r.protocol === 'ws') {
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
307
|
+
const frame = encodeWSBinary(event, buf);
|
|
308
|
+
if (r._writePaused) {
|
|
309
|
+
r._writeQueue.push(createWSBinaryFrame(frame));
|
|
310
|
+
r.info.messagesSent++;
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
const ok = r.socket.write(createWSBinaryFrame(frame));
|
|
314
|
+
if (!ok)
|
|
315
|
+
r._writePaused = true;
|
|
267
316
|
}
|
|
268
317
|
else {
|
|
269
|
-
|
|
318
|
+
const frame = encodeBinaryFrame(event, buf, this.maxFrame);
|
|
319
|
+
if (r._writePaused) {
|
|
320
|
+
r._writeQueue.push(frame);
|
|
321
|
+
r.info.messagesSent++;
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
const ok = r.socket.write(frame);
|
|
325
|
+
if (!ok)
|
|
326
|
+
r._writePaused = true;
|
|
270
327
|
}
|
|
271
328
|
r.info.messagesSent++;
|
|
272
329
|
return true;
|
|
@@ -275,6 +332,24 @@ class StelarServer {
|
|
|
275
332
|
return false;
|
|
276
333
|
}
|
|
277
334
|
}
|
|
335
|
+
_flushQueue(r) {
|
|
336
|
+
r._writePaused = false;
|
|
337
|
+
while (r._writeQueue.length) {
|
|
338
|
+
const buf = r._writeQueue.shift();
|
|
339
|
+
if (!r.socket.destroyed && !r.socket.writableEnded) {
|
|
340
|
+
try {
|
|
341
|
+
const ok = r.socket.write(buf);
|
|
342
|
+
if (!ok) {
|
|
343
|
+
r._writePaused = true;
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
278
353
|
_checkRate(cid, event) {
|
|
279
354
|
const co = this.clientRates.get(cid);
|
|
280
355
|
if (co)
|
|
@@ -295,8 +370,31 @@ class StelarServer {
|
|
|
295
370
|
}
|
|
296
371
|
return socket.remoteAddress || 'unknown';
|
|
297
372
|
}
|
|
373
|
+
/* ── Private: per-client heartbeat ── */
|
|
374
|
+
_startClientHB(r) {
|
|
375
|
+
r._hbTimer = setInterval(() => {
|
|
376
|
+
if (r.socket.destroyed) {
|
|
377
|
+
this._stopClientHB(r);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const now = Date.now();
|
|
381
|
+
if (now - r.info.lastPing > this.hbTimeout) {
|
|
382
|
+
r.socket.destroy();
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
try {
|
|
386
|
+
r.socket.write(r.protocol === 'ws' ? createWSPingFrame() : encodePingFrame());
|
|
387
|
+
}
|
|
388
|
+
catch { }
|
|
389
|
+
}, this.hbInterval);
|
|
390
|
+
r._hbTimer.unref();
|
|
391
|
+
}
|
|
392
|
+
_stopClientHB(r) { if (r._hbTimer) {
|
|
393
|
+
clearInterval(r._hbTimer);
|
|
394
|
+
r._hbTimer = null;
|
|
395
|
+
} }
|
|
298
396
|
/* ── Private: client lifecycle ── */
|
|
299
|
-
_register(socket, proto, req, parser) {
|
|
397
|
+
_register(socket, proto, req, parser, compress = false) {
|
|
300
398
|
const ip = this._getIP(socket, req);
|
|
301
399
|
if (this.clients.size >= this.maxConns) {
|
|
302
400
|
this.hooks.onMaxConnectionsReached?.({ activeConnections: this.clients.size, max: this.maxConns, ip });
|
|
@@ -322,7 +420,7 @@ class StelarServer {
|
|
|
322
420
|
}
|
|
323
421
|
const id = this._genId ? this._genId() : randomUUID();
|
|
324
422
|
const info = { id, rooms: new Set(), lastPing: Date.now(), protocol: proto, connectedAt: Date.now(), metadata: new Map(), messagesReceived: 0, messagesSent: 0, remoteAddress: ip };
|
|
325
|
-
const record = { info, socket, parser, protocol: proto };
|
|
423
|
+
const record = { info, socket, parser, protocol: proto, compress, _hbTimer: null, _writePaused: false, _writeQueue: [] };
|
|
326
424
|
this.clients.set(socket, record);
|
|
327
425
|
this.byId.set(id, record);
|
|
328
426
|
tracker.add(ip);
|
|
@@ -330,6 +428,7 @@ class StelarServer {
|
|
|
330
428
|
return record;
|
|
331
429
|
}
|
|
332
430
|
_unregister(r, ctx) {
|
|
431
|
+
this._stopClientHB(r);
|
|
333
432
|
this.hooks.onClientDisconnect?.({ clientId: r.info.id, ip: r.info.remoteAddress, protocol: r.info.protocol, rooms: new Set(r.info.rooms) });
|
|
334
433
|
for (const room of r.info.rooms) {
|
|
335
434
|
const m = this.rooms.get(room);
|
|
@@ -393,9 +492,9 @@ class StelarServer {
|
|
|
393
492
|
id: r.info.id, socket: r.socket, req, clientInfo: r.info,
|
|
394
493
|
emit: (ev, d) => { if (s._sendJson(r, ev, d))
|
|
395
494
|
s._totalSent++; },
|
|
396
|
-
send: (rid, d) => { if (s._sendJson(r, rid, { data: d, _isAck: true }))
|
|
495
|
+
send: (rid, d) => { if (s._sendJson(r, rid, { data: d, _isAck: true, _correlationId: ctx._correlationId }))
|
|
397
496
|
s._totalSent++; },
|
|
398
|
-
emitBinary: (ev, buf) => { if (s._sendBin(r, ev, buf))
|
|
497
|
+
emitBinary: (ev, buf) => { if (s._sendBin(r, ev, Buffer.from(new Uint8Array(buf))))
|
|
399
498
|
s._totalSent++; },
|
|
400
499
|
broadcast: (ev, d) => s.broadcast(ev, d, r.info.id),
|
|
401
500
|
broadcastBinary: (ev, buf) => s.broadcastBinary(ev, buf),
|
|
@@ -424,7 +523,7 @@ class StelarServer {
|
|
|
424
523
|
const p = { event: name, data: res, _isAck: true };
|
|
425
524
|
if (ctx._correlationId)
|
|
426
525
|
p._correlationId = ctx._correlationId;
|
|
427
|
-
r.socket.write(createWSTextFrame(JSON.stringify(p)));
|
|
526
|
+
r.socket.write(createWSTextFrame(JSON.stringify(p), r.compress));
|
|
428
527
|
}
|
|
429
528
|
else {
|
|
430
529
|
r.socket.write(ctx._correlationId
|
|
@@ -451,7 +550,7 @@ class StelarServer {
|
|
|
451
550
|
} };
|
|
452
551
|
run(0);
|
|
453
552
|
}
|
|
454
|
-
/* ── Private: event dispatch
|
|
553
|
+
/* ── Private: event dispatch ── */
|
|
455
554
|
_dispatch(r, ctx, event, data, correlationId) {
|
|
456
555
|
if (event === 'pong') {
|
|
457
556
|
r.info.lastPing = Date.now();
|
|
@@ -484,23 +583,6 @@ class StelarServer {
|
|
|
484
583
|
this.log.error('Wildcard error', { error: String(e) });
|
|
485
584
|
}
|
|
486
585
|
}
|
|
487
|
-
/* ── Private: heartbeat ── */
|
|
488
|
-
_startHeartbeat() {
|
|
489
|
-
this._hb = setInterval(() => {
|
|
490
|
-
const now = Date.now();
|
|
491
|
-
this.clients.forEach(r => {
|
|
492
|
-
if (now - r.info.lastPing > this.hbTimeout) {
|
|
493
|
-
r.socket.destroy();
|
|
494
|
-
}
|
|
495
|
-
else
|
|
496
|
-
try {
|
|
497
|
-
r.socket.write(r.protocol === 'ws' ? createWSPingFrame() : encodePingFrame());
|
|
498
|
-
}
|
|
499
|
-
catch { }
|
|
500
|
-
});
|
|
501
|
-
}, this.hbInterval);
|
|
502
|
-
this._hb?.unref?.();
|
|
503
|
-
}
|
|
504
586
|
/* ── Private: WS upgrade ── */
|
|
505
587
|
_wsUpgrade(req, socket, head) {
|
|
506
588
|
const path = new URL(req.url || '/', 'http://localhost').pathname;
|
|
@@ -519,12 +601,13 @@ class StelarServer {
|
|
|
519
601
|
socket.destroy();
|
|
520
602
|
return;
|
|
521
603
|
}
|
|
604
|
+
const clientCompress = this.doCompress && clientWantsCompression(req.headers['sec-websocket-extensions']);
|
|
522
605
|
try {
|
|
523
606
|
const extra = {};
|
|
524
607
|
const origin = req.headers['origin'];
|
|
525
608
|
if (origin && this.origins?.includes(origin))
|
|
526
609
|
extra['Access-Control-Allow-Origin'] = origin;
|
|
527
|
-
socket.write(buildUpgradeResponse(key, extra));
|
|
610
|
+
socket.write(buildUpgradeResponse(key, extra, clientCompress));
|
|
528
611
|
}
|
|
529
612
|
catch {
|
|
530
613
|
socket.destroy();
|
|
@@ -533,7 +616,7 @@ class StelarServer {
|
|
|
533
616
|
const timer = setTimeout(() => { if (!this.clients.has(socket))
|
|
534
617
|
socket.destroy(); }, this.connTimeout);
|
|
535
618
|
timer.unref();
|
|
536
|
-
const r = this._register(socket, 'ws', req, new WSFrameParser(this.maxWSFrame));
|
|
619
|
+
const r = this._register(socket, 'ws', req, new WSFrameParser(this.maxWSFrame), clientCompress);
|
|
537
620
|
if (!r) {
|
|
538
621
|
clearTimeout(timer);
|
|
539
622
|
return;
|
|
@@ -547,13 +630,14 @@ class StelarServer {
|
|
|
547
630
|
catch (e) {
|
|
548
631
|
this.log.error('Connection handler error', { error: String(e) });
|
|
549
632
|
} });
|
|
550
|
-
this.log.info('WS connected', { clientId: r.info.id, ip: r.info.remoteAddress });
|
|
633
|
+
this.log.info('WS connected', { clientId: r.info.id, ip: r.info.remoteAddress, compressed: clientCompress });
|
|
634
|
+
this._startClientHB(r);
|
|
551
635
|
if (head.length > 0)
|
|
552
636
|
this._processWS(r, head, ctx);
|
|
553
637
|
socket.on('data', (d) => { clearTimeout(timer); this._processWS(r, d, ctx); });
|
|
554
638
|
socket.on('close', () => { clearTimeout(timer); this._unregister(r, ctx); });
|
|
555
639
|
socket.on('error', (e) => { this.log.warn('WS error', { clientId: r.info.id, error: e.message }); this._handleErr(r, ctx, e); });
|
|
556
|
-
socket.on('drain', () =>
|
|
640
|
+
socket.on('drain', () => this._flushQueue(r));
|
|
557
641
|
}
|
|
558
642
|
_processWS(r, data, ctx) {
|
|
559
643
|
let frames;
|
|
@@ -659,7 +743,7 @@ class StelarServer {
|
|
|
659
743
|
if (corrId)
|
|
660
744
|
p._correlationId = corrId;
|
|
661
745
|
try {
|
|
662
|
-
r.socket.write(createWSTextFrame(JSON.stringify(p)));
|
|
746
|
+
r.socket.write(createWSTextFrame(JSON.stringify(p), r.compress));
|
|
663
747
|
this._totalSent++;
|
|
664
748
|
}
|
|
665
749
|
catch { }
|
|
@@ -675,39 +759,29 @@ class StelarServer {
|
|
|
675
759
|
this.hooks.onPayloadTooLarge?.({ clientId: r.info.id, size: payload.length, max: this.maxPayload });
|
|
676
760
|
return;
|
|
677
761
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
for (let i = 0; i < payload.length; i++)
|
|
681
|
-
if (payload[i] === 0) {
|
|
682
|
-
end = i;
|
|
683
|
-
break;
|
|
684
|
-
}
|
|
685
|
-
if (end === -1)
|
|
686
|
-
return;
|
|
687
|
-
const hdr = JSON.parse(payload.subarray(0, end).toString('utf8'));
|
|
688
|
-
const buf = payload.subarray(end + 1);
|
|
689
|
-
if (hdr.event && !this._checkRate(r.info.id, hdr.event)) {
|
|
690
|
-
this.log.warn('Binary rate limit', { clientId: r.info.id, event: hdr.event });
|
|
691
|
-
if (this.hooks.onRateLimitExceeded?.({ clientId: r.info.id, event: hdr.event, protocol: 'ws' }) === false)
|
|
692
|
-
return;
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
const ectx = { ...ctx, data: buf, buffer: buf, isBinary: true, event: hdr.event };
|
|
696
|
-
const h = this.events.get(hdr.event);
|
|
697
|
-
if (h)
|
|
698
|
-
try {
|
|
699
|
-
h(ectx);
|
|
700
|
-
}
|
|
701
|
-
catch { }
|
|
702
|
-
if (this._wild)
|
|
703
|
-
try {
|
|
704
|
-
this._wild({ event: hdr.event, data: ectx });
|
|
705
|
-
}
|
|
706
|
-
catch { }
|
|
707
|
-
}
|
|
708
|
-
catch {
|
|
762
|
+
const parsed = parseWSBinary(payload);
|
|
763
|
+
if (!parsed) {
|
|
709
764
|
this.hooks.onInvalidMessage?.({ clientId: r.info.id, reason: 'Invalid binary frame', protocol: 'ws' });
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
if (parsed.event && !this._checkRate(r.info.id, parsed.event)) {
|
|
768
|
+
this.log.warn('Binary rate limit', { clientId: r.info.id, event: parsed.event });
|
|
769
|
+
if (this.hooks.onRateLimitExceeded?.({ clientId: r.info.id, event: parsed.event, protocol: 'ws' }) === false)
|
|
770
|
+
return;
|
|
771
|
+
return;
|
|
710
772
|
}
|
|
773
|
+
const ectx = { ...ctx, data: parsed.buffer, buffer: parsed.buffer, isBinary: true, event: parsed.event };
|
|
774
|
+
const h = this.events.get(parsed.event);
|
|
775
|
+
if (h)
|
|
776
|
+
try {
|
|
777
|
+
h(ectx);
|
|
778
|
+
}
|
|
779
|
+
catch { }
|
|
780
|
+
if (this._wild)
|
|
781
|
+
try {
|
|
782
|
+
this._wild({ event: parsed.event, data: ectx });
|
|
783
|
+
}
|
|
784
|
+
catch { }
|
|
711
785
|
}
|
|
712
786
|
}
|
|
713
787
|
/* ── Private: TCP connection ── */
|
|
@@ -732,10 +806,11 @@ class StelarServer {
|
|
|
732
806
|
this.log.error('TCP connection handler error', { error: String(e) });
|
|
733
807
|
} });
|
|
734
808
|
this.log.info('TCP connected', { clientId: r.info.id, ip: r.info.remoteAddress });
|
|
809
|
+
this._startClientHB(r);
|
|
735
810
|
socket.on('data', (d) => this._processTCP(r, d, ctx));
|
|
736
811
|
socket.on('close', () => this._unregister(r, ctx));
|
|
737
812
|
socket.on('error', (e) => { this.log.warn('TCP error', { clientId: r.info.id, error: e.message }); this._handleErr(r, ctx, e); });
|
|
738
|
-
socket.on('drain', () =>
|
|
813
|
+
socket.on('drain', () => this._flushQueue(r));
|
|
739
814
|
}
|
|
740
815
|
_processTCP(r, data, ctx) {
|
|
741
816
|
let frames;
|
|
@@ -832,21 +907,6 @@ class StelarServer {
|
|
|
832
907
|
}
|
|
833
908
|
return;
|
|
834
909
|
}
|
|
835
|
-
if (type === FRAME_ACK_RES) {
|
|
836
|
-
try {
|
|
837
|
-
const raw = JSON.parse(payload.toString('utf8'));
|
|
838
|
-
const data = raw && typeof raw === 'object' && 'data' in raw ? raw.data : raw;
|
|
839
|
-
const corrId = raw && typeof raw === 'object' && '_correlationId' in raw ? String(raw._correlationId) : undefined;
|
|
840
|
-
const h = this._acks.get(corrId || event);
|
|
841
|
-
if (h)
|
|
842
|
-
try {
|
|
843
|
-
h({ ...ctx, data });
|
|
844
|
-
}
|
|
845
|
-
catch { }
|
|
846
|
-
}
|
|
847
|
-
catch { }
|
|
848
|
-
return;
|
|
849
|
-
}
|
|
850
910
|
if (type === FRAME_BINARY) {
|
|
851
911
|
const ectx = { ...ctx, data: payload, buffer: payload, isBinary: true, event };
|
|
852
912
|
const h = this.events.get(event);
|
|
@@ -981,7 +1041,6 @@ class StelarServer {
|
|
|
981
1041
|
this._upgH = (req, socket, head) => this._wsUpgrade(req, socket, head);
|
|
982
1042
|
srv.on('request', this._reqH);
|
|
983
1043
|
srv.on('upgrade', this._upgH);
|
|
984
|
-
this._startHeartbeat();
|
|
985
1044
|
this._rc = setInterval(() => {
|
|
986
1045
|
if (this._crl)
|
|
987
1046
|
this._crl.cleanup();
|
|
@@ -999,7 +1058,7 @@ class StelarServer {
|
|
|
999
1058
|
this._rc?.unref?.();
|
|
1000
1059
|
this._setupShutdown();
|
|
1001
1060
|
const p = this.getPort();
|
|
1002
|
-
this.log.info('Server started', { port: p, namespace: this.ns, tls: !!this.tlsOpts });
|
|
1061
|
+
this.log.info('Server started', { port: p, namespace: this.ns, tls: !!this.tlsOpts, compression: this.doCompress });
|
|
1003
1062
|
cb?.(p);
|
|
1004
1063
|
resolve(p);
|
|
1005
1064
|
};
|
|
@@ -1056,10 +1115,7 @@ class StelarServer {
|
|
|
1056
1115
|
startPlain(port, attempts);
|
|
1057
1116
|
}
|
|
1058
1117
|
stop() {
|
|
1059
|
-
|
|
1060
|
-
clearInterval(this._hb);
|
|
1061
|
-
this._hb = null;
|
|
1062
|
-
}
|
|
1118
|
+
this.clients.forEach(r => this._stopClientHB(r));
|
|
1063
1119
|
if (this._rc) {
|
|
1064
1120
|
clearInterval(this._rc);
|
|
1065
1121
|
this._rc = null;
|