stelar-time-real 1.0.3 → 1.2.0
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 +144 -3
- package/package.json +1 -1
- package/src/client.js +114 -2
- package/src/index.js +87 -1
package/README.md
CHANGED
|
@@ -13,6 +13,9 @@ Tu propio sistema de tiempo real personalizado. Una librería ligera y sin depen
|
|
|
13
13
|
- 🎯 **Personalizable** - Vos controlás todo, nada de código ajeno
|
|
14
14
|
- 🔌 **Compatible** - Funciona con Express, Fastify, HTTP nativo, etc.
|
|
15
15
|
- 💓 **Heartbeat incluido** - Detecta desconexiones automáticamente
|
|
16
|
+
- 🌐 **Namespaces** - Múltiples canales independientes (`/chat`, `/game`, etc.)
|
|
17
|
+
- ⚡ **ACK ultra rápido** - Request-response con Promesas, sin overhead
|
|
18
|
+
- 📦 **Binarios** - Envía imágenes, archivos, audio, video sin overhead de base64
|
|
16
19
|
|
|
17
20
|
## Instalación
|
|
18
21
|
|
|
@@ -190,15 +193,78 @@ stelar.on('mensaje', (ctx) => {
|
|
|
190
193
|
ctx.socket // WebSocket del cliente
|
|
191
194
|
ctx.req // Request HTTP original
|
|
192
195
|
ctx.data // Datos recibidos
|
|
193
|
-
|
|
196
|
+
|
|
194
197
|
// Métodos disponibles:
|
|
195
198
|
ctx.emit('evento', data) // Enviar solo a este cliente
|
|
199
|
+
ctx.send('respuesta', data) // Responder a un ACK
|
|
196
200
|
ctx.broadcast('evento', data) // Enviar a todos
|
|
197
201
|
ctx.to('sala', 'evento', data) // Enviar a una sala
|
|
198
202
|
ctx.toId('id', 'evento', data) // Enviar a un cliente específico
|
|
199
203
|
ctx.getClients('sala') // Ver clientes en sala
|
|
200
204
|
ctx.joinRoom('sala') // Unir a sala
|
|
201
205
|
ctx.leaveRoom() // Salir de sala
|
|
206
|
+
ctx.ack('miAck', data) // Responder a un ACK personalizado
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
#### Namespaces
|
|
211
|
+
|
|
212
|
+
Crear canales independientes:
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
import { StelarServer } from 'stelar-time-real';
|
|
216
|
+
|
|
217
|
+
// Namespace principal
|
|
218
|
+
const main = new StelarServer({ server, namespace: '/' });
|
|
219
|
+
|
|
220
|
+
// Namespace de chat
|
|
221
|
+
const chat = StelarServer.of('/chat', { server });
|
|
222
|
+
chat.on('message', (ctx) => {
|
|
223
|
+
ctx.broadcast('message', ctx.data);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Namespace de game
|
|
227
|
+
const game = StelarServer.of('/game', { server });
|
|
228
|
+
game.on('move', (ctx) => {
|
|
229
|
+
ctx.to(ctx.data.room, 'move', ctx.data);
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### ACK (Request-Response)
|
|
234
|
+
|
|
235
|
+
Sistema ultra eficiente con Promesas:
|
|
236
|
+
|
|
237
|
+
**Servidor:**
|
|
238
|
+
|
|
239
|
+
```javascript
|
|
240
|
+
// Registrar un ACK handler
|
|
241
|
+
stelar.onAck('getUser', (ctx) => {
|
|
242
|
+
return { id: ctx.data.id, name: 'John' };
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// O con lógica más compleja
|
|
246
|
+
stelar.onAck('saveData', (ctx) => {
|
|
247
|
+
const result = saveToDatabase(ctx.data);
|
|
248
|
+
return { success: true, id: result.id };
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Cliente:**
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
// Usando request() - retorna Promise
|
|
256
|
+
const user = await client.request('getUser', { id: 1 }, 'userData');
|
|
257
|
+
console.log(user); // { id: 1, name: 'John' }
|
|
258
|
+
|
|
259
|
+
// O emitiendo con callback
|
|
260
|
+
client.emit('getUser', { id: 1 }, { ack: 'userData' });
|
|
261
|
+
client.on('userData', (data) => {
|
|
262
|
+
console.log(data);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// ACK desde el servidor al cliente
|
|
266
|
+
client.onAck('serverPush', (data) => {
|
|
267
|
+
console.log('El servidor envió:', data);
|
|
202
268
|
});
|
|
203
269
|
```
|
|
204
270
|
|
|
@@ -255,11 +321,32 @@ client.onAll(({ event, data }) => {
|
|
|
255
321
|
});
|
|
256
322
|
```
|
|
257
323
|
|
|
258
|
-
**`.
|
|
259
|
-
|
|
324
|
+
**`.onAck(name, handler)`**
|
|
325
|
+
Escuchar respuestas de ACK del servidor.
|
|
326
|
+
|
|
327
|
+
```javascript
|
|
328
|
+
client.onAck('userData', (data) => {
|
|
329
|
+
console.log('Datos recibidos:', data);
|
|
330
|
+
});
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**`.emit(event, data, opts)`**
|
|
334
|
+
Enviar eventos al servidor. Soporta `opts.ack` para ACKs.
|
|
260
335
|
|
|
261
336
|
```javascript
|
|
262
337
|
client.emit('chat', { mensaje: 'Hola!' });
|
|
338
|
+
client.emit('getUser', { id: 1 }, { ack: 'userData' });
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**`.request(event, data, ackName)`**
|
|
342
|
+
Enviar y esperar respuesta como Promise.
|
|
343
|
+
|
|
344
|
+
```javascript
|
|
345
|
+
const result = await client.request('getUser', { id: 1 }, 'userData');
|
|
346
|
+
console.log(result); // { id: 1, name: 'John' }
|
|
347
|
+
|
|
348
|
+
// Con timeout opcional
|
|
349
|
+
const client = new StelarClient(3000, { ackTimeout: 10000 });
|
|
263
350
|
```
|
|
264
351
|
|
|
265
352
|
**`.joinRoom(room)`**
|
|
@@ -414,6 +501,49 @@ client.on('reconnecting', (attempt) => console.log(`Reintentando ${attempt}/5`))
|
|
|
414
501
|
client.connect();
|
|
415
502
|
```
|
|
416
503
|
|
|
504
|
+
### Enviar Archivos Binarios
|
|
505
|
+
|
|
506
|
+
```javascript
|
|
507
|
+
// Servidor - recibir imagen
|
|
508
|
+
stelar.on('image', (ctx) => {
|
|
509
|
+
// ctx.buffer es un Uint8Array
|
|
510
|
+
console.log('Recibido:', ctx.buffer.byteLength, 'bytes');
|
|
511
|
+
// Guardar o procesar la imagen
|
|
512
|
+
saveImage(ctx.buffer);
|
|
513
|
+
|
|
514
|
+
// Responder al cliente
|
|
515
|
+
ctx.emit('imageSaved', { success: true });
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
// Cliente - enviar imagen
|
|
519
|
+
const input = document.querySelector('input[type="file"]');
|
|
520
|
+
input.addEventListener('change', async (e) => {
|
|
521
|
+
const file = e.target.files[0];
|
|
522
|
+
const buffer = await file.arrayBuffer();
|
|
523
|
+
client.emitBinary('image', buffer);
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
// Cliente - recibir imagen
|
|
527
|
+
client.on('image', (buffer) => {
|
|
528
|
+
const blob = new Blob([buffer], { type: 'image/png' });
|
|
529
|
+
const url = URL.createObjectURL(blob);
|
|
530
|
+
document.getElementById('img').src = url;
|
|
531
|
+
});
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Broadcast de Binarios
|
|
535
|
+
|
|
536
|
+
```javascript
|
|
537
|
+
// Servidor - compartir archivo con todos
|
|
538
|
+
stelar.on('upload', (ctx) => {
|
|
539
|
+
ctx.broadcastBinary('file', ctx.buffer);
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
// Cliente - enviar archivo
|
|
543
|
+
const fileData = await file.arrayBuffer();
|
|
544
|
+
client.emitBinary('upload', fileData);
|
|
545
|
+
```
|
|
546
|
+
|
|
417
547
|
---
|
|
418
548
|
|
|
419
549
|
## Diferencia con Socket.io
|
|
@@ -428,6 +558,17 @@ client.connect();
|
|
|
428
558
|
|
|
429
559
|
## Changelog
|
|
430
560
|
|
|
561
|
+
### v1.2.0
|
|
562
|
+
- Soporte binarios: envía imágenes, archivos, audio, video sin base64
|
|
563
|
+
- `ctx.emitBinary('event', buffer)` y `client.emitBinary('event', buffer)`
|
|
564
|
+
- `client.sendFile(file)` y `client.sendImage(blob)`
|
|
565
|
+
- Eficiente: usa WebSocket binary diretamente, sin overhead
|
|
566
|
+
|
|
567
|
+
### v1.1.0
|
|
568
|
+
- Namespaces: `StelarServer.of('/chat')` para múltiples canales
|
|
569
|
+
- ACK personalizado: `ctx.ack('nombre', data)` y `client.request(event, data, 'ackName')`
|
|
570
|
+
- Sistema de request-response con Promesas, ultra eficiente
|
|
571
|
+
|
|
431
572
|
### v1.0.3
|
|
432
573
|
- Exportación mejorada: un solo import para servidor y cliente
|
|
433
574
|
- `import { StelarServer, StelarClient } from 'stelar-time-real'`
|
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -12,7 +12,8 @@ class StelarClient {
|
|
|
12
12
|
reconnection: options.reconnection !== false,
|
|
13
13
|
reconnectionAttempts: options.reconnectionAttempts || 5,
|
|
14
14
|
reconnectionDelay: options.reconnectionDelay || 1000,
|
|
15
|
-
heartbeatInterval: options.heartbeatInterval || 30000
|
|
15
|
+
heartbeatInterval: options.heartbeatInterval || 30000,
|
|
16
|
+
ackTimeout: options.ackTimeout || 5000
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
this.ws = null;
|
|
@@ -23,6 +24,86 @@ class StelarClient {
|
|
|
23
24
|
this._reconnectAttempts = 0;
|
|
24
25
|
this._hbTimer = null;
|
|
25
26
|
this._isManualClose = false;
|
|
27
|
+
this._acks = {};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
setUrl(url) {
|
|
31
|
+
this.url = url;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
on(event, handler) {
|
|
36
|
+
this.events[event] = handler;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
onAll(handler) {
|
|
41
|
+
this._wildcardHandler = handler;
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
onAck(name, handler) {
|
|
46
|
+
this._acks[name] = handler;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
emit(event, data, opts = {}) {
|
|
51
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
52
|
+
const payload = { event, data };
|
|
53
|
+
if (opts.ack) {
|
|
54
|
+
payload._ackName = opts.ack;
|
|
55
|
+
}
|
|
56
|
+
this.ws.send(JSON.stringify(payload));
|
|
57
|
+
}
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
emitBinary(event, data) {
|
|
62
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
63
|
+
const header = JSON.stringify({ event });
|
|
64
|
+
const headerBytes = new TextEncoder().encode(header);
|
|
65
|
+
const combined = new Uint8Array(headerBytes.length + 1 + data.byteLength);
|
|
66
|
+
combined.set(headerBytes, 0);
|
|
67
|
+
combined[headerBytes.length] = 0;
|
|
68
|
+
combined.set(new Uint8Array(data), headerBytes.length + 1);
|
|
69
|
+
this.ws.send(combined);
|
|
70
|
+
}
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
sendFile(file) {
|
|
75
|
+
return this.emitBinary('file', file);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
sendImage(blob) {
|
|
79
|
+
return this.emitBinary('image', blob);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
request(event, data, ackName) {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
const timeout = setTimeout(() => {
|
|
85
|
+
reject(new Error(`ACK '${ackName}' timeout`));
|
|
86
|
+
}, this.options.ackTimeout);
|
|
87
|
+
|
|
88
|
+
const handler = (responseData) => {
|
|
89
|
+
clearTimeout(timeout);
|
|
90
|
+
this.off(ackName, handler);
|
|
91
|
+
resolve(responseData);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
this.on(ackName, handler);
|
|
95
|
+
this.emit(event, data, { ack: ackName });
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
joinRoom(room) {
|
|
100
|
+
this.emit('join-room', room);
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
leaveRoom() {
|
|
105
|
+
this.emit('leave-room', {});
|
|
106
|
+
return this;
|
|
26
107
|
}
|
|
27
108
|
|
|
28
109
|
setUrl(url) {
|
|
@@ -83,13 +164,44 @@ class StelarClient {
|
|
|
83
164
|
this._startHeartbeat();
|
|
84
165
|
};
|
|
85
166
|
|
|
167
|
+
this.ws.binaryType = 'arraybuffer';
|
|
168
|
+
|
|
86
169
|
this.ws.onmessage = (e) => {
|
|
87
170
|
try {
|
|
171
|
+
if (e.data instanceof ArrayBuffer) {
|
|
172
|
+
const view = new Uint8Array(e.data);
|
|
173
|
+
let headerEnd = -1;
|
|
174
|
+
for (let i = 0; i < view.length; i++) {
|
|
175
|
+
if (view[i] === 0) {
|
|
176
|
+
headerEnd = i;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (headerEnd === -1) return;
|
|
181
|
+
|
|
182
|
+
const headerStr = new TextDecoder().decode(view.slice(0, headerEnd));
|
|
183
|
+
const header = JSON.parse(headerStr);
|
|
184
|
+
const buffer = view.slice(headerEnd + 1);
|
|
185
|
+
|
|
186
|
+
if (this.events[header.event]) {
|
|
187
|
+
this.events[header.event](buffer);
|
|
188
|
+
}
|
|
189
|
+
if (this._wildcardHandler) {
|
|
190
|
+
this._wildcardHandler({ event: header.event, data: buffer, buffer, isBinary: true });
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
88
195
|
const msg = JSON.parse(e.data);
|
|
89
|
-
const { event, data } = msg;
|
|
196
|
+
const { event, data, _isAck } = msg;
|
|
90
197
|
|
|
91
198
|
if (event === 'ping') return;
|
|
92
199
|
|
|
200
|
+
if (_isAck && this._acks[event]) {
|
|
201
|
+
this._acks[event](data);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
93
205
|
if (this.events[event]) this.events[event](data);
|
|
94
206
|
|
|
95
207
|
if (this._wildcardHandler) {
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ class StelarServer {
|
|
|
5
5
|
constructor(options = {}) {
|
|
6
6
|
this.port = options.port || 3000;
|
|
7
7
|
this.server = options.server || null;
|
|
8
|
+
this.namespace = options.namespace || '/';
|
|
8
9
|
this.wss = null;
|
|
9
10
|
this.clients = new Map();
|
|
10
11
|
this.events = {};
|
|
@@ -13,6 +14,15 @@ class StelarServer {
|
|
|
13
14
|
this._hbTimer = null;
|
|
14
15
|
this._wildcardHandler = null;
|
|
15
16
|
this._connectionHandler = null;
|
|
17
|
+
this._acks = {};
|
|
18
|
+
this._parent = null;
|
|
19
|
+
this._children = new Map();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static of(path, options = {}) {
|
|
23
|
+
const ns = new StelarServer({ ...options, namespace: path });
|
|
24
|
+
ns._parent = this;
|
|
25
|
+
return ns;
|
|
16
26
|
}
|
|
17
27
|
|
|
18
28
|
use(middleware) {
|
|
@@ -35,6 +45,11 @@ class StelarServer {
|
|
|
35
45
|
return this;
|
|
36
46
|
}
|
|
37
47
|
|
|
48
|
+
onAck(name, handler) {
|
|
49
|
+
this._acks[name] = handler;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
38
53
|
broadcast(event, data) {
|
|
39
54
|
this.clients.forEach((info, client) => {
|
|
40
55
|
client.send(JSON.stringify({ event, data }));
|
|
@@ -42,6 +57,20 @@ class StelarServer {
|
|
|
42
57
|
return this;
|
|
43
58
|
}
|
|
44
59
|
|
|
60
|
+
broadcastBinary(event, buffer) {
|
|
61
|
+
const header = JSON.stringify({ event, _binary: true });
|
|
62
|
+
const headerBytes = new TextEncoder().encode(header);
|
|
63
|
+
const combined = new Uint8Array(headerBytes.length + 1 + buffer.byteLength);
|
|
64
|
+
combined.set(headerBytes, 0);
|
|
65
|
+
combined[headerBytes.length] = 0;
|
|
66
|
+
combined.set(new Uint8Array(buffer), headerBytes.length + 1);
|
|
67
|
+
|
|
68
|
+
this.clients.forEach((info, client) => {
|
|
69
|
+
client.send(combined);
|
|
70
|
+
});
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
|
|
45
74
|
to(room, event, data) {
|
|
46
75
|
this.clients.forEach((info, client) => {
|
|
47
76
|
if (info.room === room) {
|
|
@@ -98,6 +127,14 @@ class StelarServer {
|
|
|
98
127
|
}
|
|
99
128
|
|
|
100
129
|
_handleConnection(client, req) {
|
|
130
|
+
const urlPath = new URL(req.url, `http://localhost`).pathname;
|
|
131
|
+
const nsPath = this.namespace === '/' ? '/' : this.namespace;
|
|
132
|
+
|
|
133
|
+
if (nsPath !== '/' && urlPath !== nsPath) {
|
|
134
|
+
client.close();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
101
138
|
const clientId = Math.random().toString(36).substring(7);
|
|
102
139
|
const clientInfo = { id: clientId, room: null, lastPing: Date.now() };
|
|
103
140
|
this.clients.set(client, clientInfo);
|
|
@@ -107,7 +144,10 @@ class StelarServer {
|
|
|
107
144
|
socket: client,
|
|
108
145
|
req,
|
|
109
146
|
emit: (evt, d) => client.send(JSON.stringify({ event: evt, data: d })),
|
|
147
|
+
send: (respId, d) => client.send(JSON.stringify({ event: respId, data: d, _isAck: true })),
|
|
148
|
+
emitBinary: (evt, buffer) => client.send(buffer),
|
|
110
149
|
broadcast: (evt, d) => this.broadcast(evt, d),
|
|
150
|
+
broadcastBinary: (evt, buffer) => this.broadcastBinary(evt, buffer),
|
|
111
151
|
to: (room, evt, d) => this.to(room, evt, d),
|
|
112
152
|
toId: (id, evt, d) => this.toId(id, evt, d),
|
|
113
153
|
getClients: (room) => this.getClients(room),
|
|
@@ -117,6 +157,15 @@ class StelarServer {
|
|
|
117
157
|
},
|
|
118
158
|
leaveRoom: () => {
|
|
119
159
|
clientInfo.room = null;
|
|
160
|
+
},
|
|
161
|
+
ack: (ackName, data) => {
|
|
162
|
+
const ackHandler = this._acks[ackName];
|
|
163
|
+
if (ackHandler) {
|
|
164
|
+
const result = ackHandler({ ...ctx, data });
|
|
165
|
+
if (result !== undefined) {
|
|
166
|
+
client.send(JSON.stringify({ event: ackName, data: result, _isAck: true }));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
120
169
|
}
|
|
121
170
|
};
|
|
122
171
|
|
|
@@ -126,7 +175,35 @@ class StelarServer {
|
|
|
126
175
|
}
|
|
127
176
|
});
|
|
128
177
|
|
|
129
|
-
client.on('message', (raw) => {
|
|
178
|
+
client.on('message', (raw, isBinary) => {
|
|
179
|
+
if (isBinary) {
|
|
180
|
+
try {
|
|
181
|
+
const view = new Uint8Array(raw);
|
|
182
|
+
let headerEnd = -1;
|
|
183
|
+
for (let i = 0; i < view.length; i++) {
|
|
184
|
+
if (view[i] === 0) {
|
|
185
|
+
headerEnd = i;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (headerEnd === -1) return;
|
|
190
|
+
|
|
191
|
+
const headerStr = new TextDecoder().decode(view.slice(0, headerEnd));
|
|
192
|
+
const header = JSON.parse(headerStr);
|
|
193
|
+
const data = view.slice(headerEnd + 1);
|
|
194
|
+
|
|
195
|
+
const eventCtx = { ...ctx, data, buffer: data, isBinary: true };
|
|
196
|
+
|
|
197
|
+
if (this.events[header.event]) {
|
|
198
|
+
this.events[header.event](eventCtx);
|
|
199
|
+
}
|
|
200
|
+
if (this._wildcardHandler) {
|
|
201
|
+
this._wildcardHandler({ event: header.event, data: eventCtx });
|
|
202
|
+
}
|
|
203
|
+
} catch (e) {}
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
130
207
|
try {
|
|
131
208
|
const msg = JSON.parse(raw);
|
|
132
209
|
const { event, data } = msg;
|
|
@@ -146,6 +223,15 @@ class StelarServer {
|
|
|
146
223
|
client.send(JSON.stringify({ event: 'left-room', data }));
|
|
147
224
|
}
|
|
148
225
|
|
|
226
|
+
if (msg._ackName && this._acks[msg._ackName]) {
|
|
227
|
+
const ackHandler = this._acks[msg._ackName];
|
|
228
|
+
const result = ackHandler({ ...ctx, data });
|
|
229
|
+
if (result !== undefined) {
|
|
230
|
+
client.send(JSON.stringify({ event: msg._ackName, data: result, _isAck: true }));
|
|
231
|
+
}
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
149
235
|
const eventCtx = { ...ctx, data };
|
|
150
236
|
|
|
151
237
|
if (this.events[event]) {
|