@socket-mesh/core 1.0.3 → 2.0.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/dist/index.d.ts +10 -10
- package/dist/index.js +10 -10
- package/dist/maps/handler-map.d.ts +6 -4
- package/dist/maps/index.d.ts +2 -2
- package/dist/maps/index.js +2 -2
- package/dist/maps/method-map.d.ts +10 -8
- package/dist/maps/method-map.js +1 -0
- package/dist/packet.d.ts +33 -18
- package/dist/packet.js +3 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/index.js +1 -1
- package/dist/plugins/plugin.d.ts +40 -40
- package/dist/request-handler.d.ts +12 -10
- package/dist/request-handler.js +9 -2
- package/dist/request.d.ts +36 -43
- package/dist/request.js +13 -11
- package/dist/response.d.ts +18 -14
- package/dist/response.js +3 -1
- package/dist/socket-event.d.ts +31 -27
- package/dist/socket-transport.d.ts +63 -60
- package/dist/socket-transport.js +232 -205
- package/dist/socket.d.ts +43 -37
- package/dist/socket.js +22 -17
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +6 -3
- package/package.json +15 -12
package/dist/socket-transport.js
CHANGED
|
@@ -1,15 +1,37 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { toArray, wait } from
|
|
10
|
-
export class
|
|
1
|
+
import { extractAuthTokenData } from '@socket-mesh/auth';
|
|
2
|
+
import { AbortError, AuthError, BadConnectionError, dehydrateError, hydrateError, InvalidActionError, InvalidArgumentsError, PluginBlockedError, SocketClosedError, SocketProtocolError, SocketProtocolErrorStatuses, SocketProtocolIgnoreStatuses, TimeoutError } from '@socket-mesh/errors';
|
|
3
|
+
import defaultCodec from '@socket-mesh/formatter';
|
|
4
|
+
import ws from 'isomorphic-ws';
|
|
5
|
+
import { isRequestPacket } from './packet.js';
|
|
6
|
+
import { RequestHandlerArgs } from './request-handler.js';
|
|
7
|
+
import { abortRequest, isRequestDone } from './request.js';
|
|
8
|
+
import { isResponsePacket } from './response.js';
|
|
9
|
+
import { toArray, toError, wait } from './utils.js';
|
|
10
|
+
export class BaseSocketTransport {
|
|
11
|
+
_authToken;
|
|
12
|
+
_callbackMap;
|
|
13
|
+
_callIdGenerator;
|
|
14
|
+
_handlers;
|
|
15
|
+
_inboundProcessedMessageCount;
|
|
16
|
+
_inboundReceivedMessageCount;
|
|
17
|
+
_isReady;
|
|
18
|
+
_outboundPreparedMessageCount;
|
|
19
|
+
_outboundSentMessageCount;
|
|
20
|
+
_pingTimeoutRef;
|
|
21
|
+
_signedAuthToken;
|
|
22
|
+
_socket;
|
|
23
|
+
_webSocket;
|
|
24
|
+
ackTimeoutMs;
|
|
25
|
+
codecEngine;
|
|
26
|
+
id;
|
|
27
|
+
plugins;
|
|
28
|
+
streamCleanupMode;
|
|
11
29
|
constructor(options) {
|
|
12
30
|
let cid = 1;
|
|
31
|
+
this._isReady = false;
|
|
32
|
+
this._authToken = null;
|
|
33
|
+
this._signedAuthToken = null;
|
|
34
|
+
this._webSocket = null;
|
|
13
35
|
this.ackTimeoutMs = options?.ackTimeoutMs ?? 10000;
|
|
14
36
|
this._callIdGenerator = options?.callIdGenerator || (() => {
|
|
15
37
|
return cid++;
|
|
@@ -42,10 +64,10 @@ export class SocketTransport {
|
|
|
42
64
|
const signedAuthToken = this._signedAuthToken;
|
|
43
65
|
this._authToken = null;
|
|
44
66
|
this._signedAuthToken = null;
|
|
45
|
-
this._socket.emit('authStateChange', {
|
|
67
|
+
this._socket.emit('authStateChange', { isAuthenticated: false, wasAuthenticated: true });
|
|
46
68
|
// In order for the events to trigger we need to wait for the next tick.
|
|
47
69
|
await wait(0);
|
|
48
|
-
this._socket.emit('deauthenticate', {
|
|
70
|
+
this._socket.emit('deauthenticate', { authToken, signedAuthToken });
|
|
49
71
|
for (const plugin of this.plugins) {
|
|
50
72
|
if (plugin.onDeauthenticate) {
|
|
51
73
|
plugin.onDeauthenticate({ socket: this.socket, transport: this });
|
|
@@ -60,10 +82,11 @@ export class SocketTransport {
|
|
|
60
82
|
return this.codecEngine.decode(data);
|
|
61
83
|
}
|
|
62
84
|
catch (err) {
|
|
63
|
-
|
|
64
|
-
|
|
85
|
+
const error = toError(err);
|
|
86
|
+
if (error.name === 'Error') {
|
|
87
|
+
error.name = 'InvalidMessageError';
|
|
65
88
|
}
|
|
66
|
-
this.onError(
|
|
89
|
+
this.onError(error);
|
|
67
90
|
return null;
|
|
68
91
|
}
|
|
69
92
|
}
|
|
@@ -92,14 +115,14 @@ export class SocketTransport {
|
|
|
92
115
|
try {
|
|
93
116
|
for (const plugin of this.plugins) {
|
|
94
117
|
if (plugin.onMessage) {
|
|
95
|
-
curPacket = await plugin.onMessage({
|
|
118
|
+
curPacket = await plugin.onMessage({ packet: curPacket, socket: this.socket, timestamp: timestamp, transport: this });
|
|
96
119
|
}
|
|
97
120
|
}
|
|
98
121
|
}
|
|
99
122
|
catch (err) {
|
|
100
|
-
pluginError = err;
|
|
123
|
+
pluginError = toError(err);
|
|
101
124
|
}
|
|
102
|
-
// Check to see if it is a request or response packet.
|
|
125
|
+
// Check to see if it is a request or response packet.
|
|
103
126
|
if (isResponsePacket(curPacket)) {
|
|
104
127
|
this.onResponse(curPacket, pluginError);
|
|
105
128
|
}
|
|
@@ -111,19 +134,105 @@ export class SocketTransport {
|
|
|
111
134
|
}
|
|
112
135
|
}
|
|
113
136
|
}
|
|
137
|
+
invoke(methodOptions, arg) {
|
|
138
|
+
let methodRequest;
|
|
139
|
+
let serviceRequest;
|
|
140
|
+
let service;
|
|
141
|
+
let ackTimeoutMs;
|
|
142
|
+
if (typeof methodOptions === 'object' && !Array.isArray(methodOptions)) {
|
|
143
|
+
ackTimeoutMs = methodOptions.ackTimeoutMs;
|
|
144
|
+
}
|
|
145
|
+
if (typeof methodOptions === 'object' && (Array.isArray(methodOptions) || 'service' in methodOptions)) {
|
|
146
|
+
let serviceMethod;
|
|
147
|
+
if (Array.isArray(methodOptions)) {
|
|
148
|
+
service = methodOptions[0];
|
|
149
|
+
serviceMethod = methodOptions[1];
|
|
150
|
+
ackTimeoutMs = methodOptions[2];
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
service = methodOptions.service;
|
|
154
|
+
serviceMethod = methodOptions.method;
|
|
155
|
+
}
|
|
156
|
+
serviceRequest = {
|
|
157
|
+
ackTimeoutMs: ackTimeoutMs || this.ackTimeoutMs,
|
|
158
|
+
callback: null,
|
|
159
|
+
cid: this._callIdGenerator(),
|
|
160
|
+
data: arg,
|
|
161
|
+
method: serviceMethod,
|
|
162
|
+
service: service
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
methodRequest = {
|
|
167
|
+
ackTimeoutMs: ackTimeoutMs || this.ackTimeoutMs,
|
|
168
|
+
callback: null,
|
|
169
|
+
cid: this._callIdGenerator(),
|
|
170
|
+
data: arg,
|
|
171
|
+
method: (typeof methodOptions === 'object') ? methodOptions.method : methodOptions
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const callbackMap = this._callbackMap;
|
|
175
|
+
let abort;
|
|
176
|
+
const baseRequest = (serviceRequest || methodRequest);
|
|
177
|
+
const promise = new Promise((resolve, reject) => {
|
|
178
|
+
if (baseRequest.ackTimeoutMs) {
|
|
179
|
+
baseRequest.timeoutId = setTimeout(() => {
|
|
180
|
+
delete callbackMap[baseRequest.cid];
|
|
181
|
+
baseRequest.callback = null;
|
|
182
|
+
clearTimeout(baseRequest.timeoutId);
|
|
183
|
+
delete baseRequest.timeoutId;
|
|
184
|
+
reject(new TimeoutError(`Method '${[service, baseRequest.method].filter(Boolean).join('.')}' timed out.`));
|
|
185
|
+
}, baseRequest.ackTimeoutMs);
|
|
186
|
+
}
|
|
187
|
+
abort = () => {
|
|
188
|
+
delete callbackMap[baseRequest.cid];
|
|
189
|
+
if (baseRequest.timeoutId) {
|
|
190
|
+
clearTimeout(baseRequest.timeoutId);
|
|
191
|
+
delete baseRequest.timeoutId;
|
|
192
|
+
}
|
|
193
|
+
if (baseRequest.callback) {
|
|
194
|
+
baseRequest.callback = null;
|
|
195
|
+
reject(new AbortError(`Method '${[service, baseRequest.method].filter(Boolean).join('.')}' was aborted.`));
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
baseRequest.callback = (err, result) => {
|
|
199
|
+
delete callbackMap[baseRequest.cid];
|
|
200
|
+
baseRequest.callback = null;
|
|
201
|
+
if (baseRequest.timeoutId) {
|
|
202
|
+
clearTimeout(baseRequest.timeoutId);
|
|
203
|
+
delete baseRequest.timeoutId;
|
|
204
|
+
}
|
|
205
|
+
if (err) {
|
|
206
|
+
reject(err);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
resolve(result);
|
|
210
|
+
};
|
|
211
|
+
baseRequest.sentCallback = () => {
|
|
212
|
+
delete baseRequest.sentCallback;
|
|
213
|
+
this._outboundSentMessageCount++;
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
this._outboundPreparedMessageCount++;
|
|
217
|
+
const request = Object.assign(baseRequest, { promise });
|
|
218
|
+
this.onInvoke(request);
|
|
219
|
+
return [promise, abort];
|
|
220
|
+
}
|
|
114
221
|
onClose(code, reason) {
|
|
115
222
|
const prevStatus = this.status;
|
|
116
223
|
this.webSocket = null;
|
|
117
224
|
this._isReady = false;
|
|
118
|
-
|
|
119
|
-
|
|
225
|
+
if (this._pingTimeoutRef) {
|
|
226
|
+
clearTimeout(this._pingTimeoutRef);
|
|
227
|
+
this._pingTimeoutRef = null;
|
|
228
|
+
}
|
|
120
229
|
this.abortAllPendingCallbacksDueToBadConnection(prevStatus);
|
|
121
230
|
for (const plugin of this.plugins) {
|
|
122
231
|
if (plugin.onClose) {
|
|
123
232
|
plugin.onClose({ socket: this.socket, transport: this });
|
|
124
233
|
}
|
|
125
234
|
}
|
|
126
|
-
if (!
|
|
235
|
+
if (!SocketProtocolIgnoreStatuses[code]) {
|
|
127
236
|
let closeMessage;
|
|
128
237
|
if (typeof reason === 'string') {
|
|
129
238
|
closeMessage = `Socket connection closed with status code ${code} and reason: ${reason}`;
|
|
@@ -131,9 +240,9 @@ export class SocketTransport {
|
|
|
131
240
|
else {
|
|
132
241
|
closeMessage = `Socket connection closed with status code ${code}`;
|
|
133
242
|
}
|
|
134
|
-
this.onError(new SocketProtocolError(
|
|
243
|
+
this.onError(new SocketProtocolError(SocketProtocolErrorStatuses[code] || closeMessage, code));
|
|
135
244
|
}
|
|
136
|
-
const strReason = reason?.toString() ||
|
|
245
|
+
const strReason = reason?.toString() || SocketProtocolErrorStatuses[code];
|
|
137
246
|
this._socket.emit('close', { code, reason: strReason });
|
|
138
247
|
}
|
|
139
248
|
onDisconnect(status, code, reason) {
|
|
@@ -145,7 +254,7 @@ export class SocketTransport {
|
|
|
145
254
|
}
|
|
146
255
|
for (const plugin of this.plugins) {
|
|
147
256
|
if (plugin.onDisconnected) {
|
|
148
|
-
plugin.onDisconnected({ socket: this.socket, transport: this
|
|
257
|
+
plugin.onDisconnected({ code, reason, socket: this.socket, status, transport: this });
|
|
149
258
|
}
|
|
150
259
|
}
|
|
151
260
|
}
|
|
@@ -172,19 +281,19 @@ export class SocketTransport {
|
|
|
172
281
|
this._inboundReceivedMessageCount++;
|
|
173
282
|
for (let i = 0; i < this.plugins.length; i++) {
|
|
174
283
|
const plugin = this.plugins[i];
|
|
175
|
-
if (plugin
|
|
176
|
-
p = p.then(message => {
|
|
177
|
-
return plugin.onMessageRaw({ socket: this.socket, transport: this
|
|
284
|
+
if (plugin?.onMessageRaw) {
|
|
285
|
+
p = p.then((message) => {
|
|
286
|
+
return plugin.onMessageRaw({ message, promise, socket: this.socket, timestamp, transport: this });
|
|
178
287
|
});
|
|
179
288
|
}
|
|
180
289
|
}
|
|
181
|
-
p.then(data => {
|
|
290
|
+
p.then((data) => {
|
|
182
291
|
const packet = this.decode(data);
|
|
183
292
|
this._socket.emit('message', { data, isBinary });
|
|
184
293
|
return this.handleInboudMessage({ packet, timestamp });
|
|
185
294
|
})
|
|
186
295
|
.then(resolve)
|
|
187
|
-
.catch(err => {
|
|
296
|
+
.catch((err) => {
|
|
188
297
|
reject(err);
|
|
189
298
|
if (!(err instanceof PluginBlockedError)) {
|
|
190
299
|
this.onError(err);
|
|
@@ -204,14 +313,16 @@ export class SocketTransport {
|
|
|
204
313
|
onPingPong() { }
|
|
205
314
|
async onRequest(packet, timestamp, pluginError) {
|
|
206
315
|
this._socket.emit('request', { request: packet });
|
|
207
|
-
const timeoutAt = typeof packet.ackTimeoutMs === 'number' ? new Date(timestamp.valueOf() + packet.ackTimeoutMs) :
|
|
316
|
+
const timeoutAt = typeof packet.ackTimeoutMs === 'number' ? new Date(timestamp.valueOf() + packet.ackTimeoutMs) : undefined;
|
|
208
317
|
let wasHandled = false;
|
|
209
318
|
let response;
|
|
210
319
|
let error;
|
|
211
320
|
if (pluginError) {
|
|
212
321
|
wasHandled = true;
|
|
213
322
|
error = pluginError;
|
|
214
|
-
|
|
323
|
+
if (packet.cid) {
|
|
324
|
+
response = { error: pluginError, rid: packet.cid, timeoutAt };
|
|
325
|
+
}
|
|
215
326
|
}
|
|
216
327
|
else {
|
|
217
328
|
const handler = this._handlers[packet.method];
|
|
@@ -220,20 +331,20 @@ export class SocketTransport {
|
|
|
220
331
|
try {
|
|
221
332
|
const data = await handler(new RequestHandlerArgs({
|
|
222
333
|
isRpc: !!packet.cid,
|
|
223
|
-
method: packet.method
|
|
224
|
-
|
|
334
|
+
method: packet.method,
|
|
335
|
+
options: packet.data,
|
|
225
336
|
socket: this._socket,
|
|
226
|
-
|
|
227
|
-
|
|
337
|
+
timeoutMs: packet.ackTimeoutMs,
|
|
338
|
+
transport: this
|
|
228
339
|
}));
|
|
229
340
|
if (packet.cid) {
|
|
230
|
-
response = { rid: packet.cid, timeoutAt
|
|
341
|
+
response = { data, rid: packet.cid, timeoutAt };
|
|
231
342
|
}
|
|
232
343
|
}
|
|
233
344
|
catch (err) {
|
|
234
|
-
error = err;
|
|
345
|
+
error = toError(err);
|
|
235
346
|
if (packet.cid) {
|
|
236
|
-
response = { rid: packet.cid, timeoutAt
|
|
347
|
+
response = { error, rid: packet.cid, timeoutAt };
|
|
237
348
|
}
|
|
238
349
|
}
|
|
239
350
|
}
|
|
@@ -267,7 +378,7 @@ export class SocketTransport {
|
|
|
267
378
|
}
|
|
268
379
|
}
|
|
269
380
|
if (pluginError) {
|
|
270
|
-
this._socket.emit('response', { response: { rid: response.rid
|
|
381
|
+
this._socket.emit('response', { response: { error: pluginError, rid: response.rid } });
|
|
271
382
|
}
|
|
272
383
|
else {
|
|
273
384
|
this._socket.emit('response', { response });
|
|
@@ -285,10 +396,7 @@ export class SocketTransport {
|
|
|
285
396
|
onTransmit(request) {
|
|
286
397
|
this.sendRequest([request]);
|
|
287
398
|
}
|
|
288
|
-
onUnhandledRequest(
|
|
289
|
-
if (this._onUnhandledRequest) {
|
|
290
|
-
return this._onUnhandledRequest(this, packet);
|
|
291
|
-
}
|
|
399
|
+
onUnhandledRequest(_) {
|
|
292
400
|
return false;
|
|
293
401
|
}
|
|
294
402
|
resetPingTimeout(timeoutMs, code) {
|
|
@@ -302,24 +410,25 @@ export class SocketTransport {
|
|
|
302
410
|
// Delay should be equal to the interval at which your server
|
|
303
411
|
// sends out pings plus a conservative assumption of the latency.
|
|
304
412
|
this._pingTimeoutRef = setTimeout(() => {
|
|
305
|
-
this.
|
|
413
|
+
if (this._webSocket) {
|
|
414
|
+
this._webSocket.close(code);
|
|
415
|
+
}
|
|
306
416
|
}, timeoutMs);
|
|
307
417
|
}
|
|
308
418
|
}
|
|
309
419
|
send(data) {
|
|
310
420
|
return new Promise((resolve, reject) => {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
reject(err);
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
resolve();
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
catch (err) {
|
|
321
|
-
throw err;
|
|
421
|
+
if (!this._webSocket) {
|
|
422
|
+
reject(new SocketClosedError('Web socket is closed.'));
|
|
423
|
+
return;
|
|
322
424
|
}
|
|
425
|
+
this._webSocket.send(data, (err) => {
|
|
426
|
+
if (err) {
|
|
427
|
+
reject(err);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
resolve();
|
|
431
|
+
});
|
|
323
432
|
});
|
|
324
433
|
}
|
|
325
434
|
sendRequest(index, requests) {
|
|
@@ -327,6 +436,9 @@ export class SocketTransport {
|
|
|
327
436
|
requests = index;
|
|
328
437
|
index = 0;
|
|
329
438
|
}
|
|
439
|
+
if (!requests) {
|
|
440
|
+
return; // Shouldn't happen
|
|
441
|
+
}
|
|
330
442
|
// Filter out any requests that have already timed out.
|
|
331
443
|
if (requests.some(request => isRequestDone(request))) {
|
|
332
444
|
requests = requests.filter(req => isRequestDone(req));
|
|
@@ -336,19 +448,20 @@ export class SocketTransport {
|
|
|
336
448
|
}
|
|
337
449
|
for (; index < this.plugins.length; index++) {
|
|
338
450
|
const plugin = this.plugins[index];
|
|
339
|
-
if (
|
|
451
|
+
if (plugin?.sendRequest) {
|
|
340
452
|
index++;
|
|
341
453
|
try {
|
|
342
454
|
plugin.sendRequest({
|
|
343
|
-
|
|
344
|
-
transport: this,
|
|
455
|
+
cont: this.sendRequest.bind(this, index),
|
|
345
456
|
requests,
|
|
346
|
-
|
|
457
|
+
socket: this.socket,
|
|
458
|
+
transport: this
|
|
347
459
|
});
|
|
348
460
|
}
|
|
349
461
|
catch (err) {
|
|
462
|
+
const error = toError(err);
|
|
350
463
|
for (const req of requests) {
|
|
351
|
-
abortRequest(req,
|
|
464
|
+
abortRequest(req, error);
|
|
352
465
|
}
|
|
353
466
|
}
|
|
354
467
|
return;
|
|
@@ -363,13 +476,13 @@ export class SocketTransport {
|
|
|
363
476
|
}
|
|
364
477
|
return;
|
|
365
478
|
}
|
|
366
|
-
const encode = requests.map(req => {
|
|
367
|
-
if ('callback' in req) {
|
|
479
|
+
const encode = requests.map((req) => {
|
|
480
|
+
if ('callback' in req && req.callback) {
|
|
368
481
|
const { callback, promise, timeoutId, ...rest } = req;
|
|
369
482
|
this._callbackMap[req.cid] = {
|
|
483
|
+
callback: req.callback,
|
|
370
484
|
method: ['service' in req ? req.service : '', req.method].filter(Boolean).join('.'),
|
|
371
|
-
timeoutId: req.timeoutId
|
|
372
|
-
callback: req.callback
|
|
485
|
+
timeoutId: req.timeoutId
|
|
373
486
|
};
|
|
374
487
|
return rest;
|
|
375
488
|
}
|
|
@@ -377,7 +490,7 @@ export class SocketTransport {
|
|
|
377
490
|
return rest;
|
|
378
491
|
});
|
|
379
492
|
let sendErr;
|
|
380
|
-
this.send(this.codecEngine.encode(encode.length === 1 ? encode[0] : encode)).catch(err => {
|
|
493
|
+
this.send(this.codecEngine.encode(encode.length === 1 ? encode[0] : encode)).catch((err) => {
|
|
381
494
|
sendErr = err;
|
|
382
495
|
}).then(() => {
|
|
383
496
|
const errCode = sendErr?.code;
|
|
@@ -388,11 +501,11 @@ export class SocketTransport {
|
|
|
388
501
|
if (req.sentCallback) {
|
|
389
502
|
req.sentCallback(sendErr);
|
|
390
503
|
}
|
|
391
|
-
if (sendErr && 'callback' in req) {
|
|
504
|
+
if (sendErr && 'callback' in req && req.callback) {
|
|
392
505
|
req.callback(sendErr);
|
|
393
506
|
}
|
|
394
507
|
}
|
|
395
|
-
}).catch(err => {
|
|
508
|
+
}).catch((err) => {
|
|
396
509
|
this.onError(err);
|
|
397
510
|
});
|
|
398
511
|
}
|
|
@@ -401,31 +514,34 @@ export class SocketTransport {
|
|
|
401
514
|
responses = index;
|
|
402
515
|
index = 0;
|
|
403
516
|
}
|
|
517
|
+
if (!responses) {
|
|
518
|
+
return; // shouldn't happen
|
|
519
|
+
}
|
|
404
520
|
// Remove any response that has timed out
|
|
405
521
|
if (!(responses = responses.filter(item => !item.timeoutAt || item.timeoutAt > new Date())).length) {
|
|
406
522
|
return;
|
|
407
523
|
}
|
|
408
524
|
for (; index < this.plugins.length; index++) {
|
|
409
525
|
const plugin = this.plugins[index];
|
|
410
|
-
if ('sendResponse' in plugin) {
|
|
526
|
+
if (plugin && 'sendResponse' in plugin && plugin.sendResponse) {
|
|
411
527
|
index++;
|
|
412
528
|
try {
|
|
413
529
|
plugin.sendResponse({
|
|
414
|
-
|
|
415
|
-
transport: this,
|
|
530
|
+
cont: this.sendResponse.bind(this, index),
|
|
416
531
|
responses,
|
|
417
|
-
|
|
532
|
+
socket: this.socket,
|
|
533
|
+
transport: this
|
|
418
534
|
});
|
|
419
535
|
}
|
|
420
536
|
catch (err) {
|
|
421
|
-
this.sendResponse(index, responses.map(item => ({ rid: item.rid, timeoutAt: item.timeoutAt
|
|
537
|
+
this.sendResponse(index, responses.map(item => ({ error: err, rid: item.rid, timeoutAt: item.timeoutAt })));
|
|
422
538
|
}
|
|
423
539
|
return;
|
|
424
540
|
}
|
|
425
541
|
}
|
|
426
542
|
// If the socket is closed we need to call them back with an error.
|
|
427
543
|
if (this.status === 'closed') {
|
|
428
|
-
for (const
|
|
544
|
+
for (const _ of responses) {
|
|
429
545
|
this.onError(new Error(`WebSocket is not open: readyState 3 (CLOSED)`));
|
|
430
546
|
}
|
|
431
547
|
return;
|
|
@@ -436,25 +552,23 @@ export class SocketTransport {
|
|
|
436
552
|
}
|
|
437
553
|
delete response.timeoutAt;
|
|
438
554
|
}
|
|
439
|
-
//timeoutId?: NodeJS.Timeout;
|
|
440
|
-
//callback: (err: Error, result?: U) => void | null
|
|
441
|
-
this.send(this.codecEngine.encode(responses.length === 1 ? responses[0] : responses)).catch(err => {
|
|
555
|
+
// timeoutId?: NodeJS.Timeout;
|
|
556
|
+
// callback: (err: Error, result?: U) => void | null
|
|
557
|
+
this.send(this.codecEngine.encode(responses.length === 1 ? responses[0] : responses)).catch((err) => {
|
|
442
558
|
this.onError(err);
|
|
443
559
|
});
|
|
444
560
|
}
|
|
445
561
|
async setAuthorization(signedAuthToken, authToken) {
|
|
446
|
-
if (typeof signedAuthToken !== 'string') {
|
|
447
|
-
throw new InvalidArgumentsError('SignedAuthToken must be type string.');
|
|
448
|
-
}
|
|
449
562
|
if (signedAuthToken !== this._signedAuthToken) {
|
|
450
|
-
|
|
563
|
+
let newAuthToken = authToken;
|
|
564
|
+
if (!newAuthToken) {
|
|
451
565
|
const extractedAuthToken = extractAuthTokenData(signedAuthToken);
|
|
452
566
|
if (typeof extractedAuthToken === 'string') {
|
|
453
567
|
throw new InvalidArgumentsError('Invalid authToken.');
|
|
454
568
|
}
|
|
455
|
-
|
|
569
|
+
newAuthToken = extractedAuthToken;
|
|
456
570
|
}
|
|
457
|
-
this._authToken =
|
|
571
|
+
this._authToken = newAuthToken;
|
|
458
572
|
this._signedAuthToken = signedAuthToken;
|
|
459
573
|
return true;
|
|
460
574
|
}
|
|
@@ -470,7 +584,7 @@ export class SocketTransport {
|
|
|
470
584
|
plugin.onReady({ socket: this.socket, transport: this });
|
|
471
585
|
}
|
|
472
586
|
}
|
|
473
|
-
this._socket.emit('connect', { id: this.id,
|
|
587
|
+
this._socket.emit('connect', { authError, id: this.id, isAuthenticated: !!this.signedAuthToken, pingTimeoutMs });
|
|
474
588
|
}
|
|
475
589
|
get signedAuthToken() {
|
|
476
590
|
return this._signedAuthToken;
|
|
@@ -489,48 +603,35 @@ export class SocketTransport {
|
|
|
489
603
|
return 'ready';
|
|
490
604
|
}
|
|
491
605
|
switch (this._webSocket.readyState) {
|
|
606
|
+
case ws.CLOSING:
|
|
607
|
+
return 'closing';
|
|
492
608
|
case ws.CONNECTING:
|
|
493
609
|
case ws.OPEN:
|
|
494
610
|
return 'connecting';
|
|
495
|
-
case ws.CLOSING:
|
|
496
|
-
return 'closing';
|
|
497
611
|
default:
|
|
498
612
|
return 'closed';
|
|
499
613
|
}
|
|
500
614
|
}
|
|
501
|
-
triggerAuthenticationEvents(wasSigned, wasAuthenticated) {
|
|
502
|
-
this._socket.emit('authStateChange', { wasAuthenticated, isAuthenticated: true, authToken: this._authToken, signedAuthToken: this._signedAuthToken });
|
|
503
|
-
this._socket.emit('authenticate', { wasSigned, signedAuthToken: this._signedAuthToken, authToken: this._authToken });
|
|
504
|
-
for (const plugin of this.plugins) {
|
|
505
|
-
if (plugin.onAuthenticated) {
|
|
506
|
-
plugin.onAuthenticated({ socket: this.socket, transport: this });
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
615
|
transmit(serviceAndMethod, arg) {
|
|
511
|
-
let
|
|
512
|
-
let
|
|
513
|
-
let method;
|
|
616
|
+
let serviceRequest;
|
|
617
|
+
let methodRequest;
|
|
514
618
|
if (Array.isArray(serviceAndMethod)) {
|
|
515
|
-
|
|
516
|
-
|
|
619
|
+
serviceRequest = {
|
|
620
|
+
data: arg,
|
|
621
|
+
method: serviceAndMethod[1],
|
|
622
|
+
service: serviceAndMethod[0]
|
|
623
|
+
};
|
|
517
624
|
}
|
|
518
625
|
else {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
method,
|
|
529
|
-
promise: null
|
|
530
|
-
};
|
|
531
|
-
const promise = request.promise = new Promise((resolve, reject) => {
|
|
532
|
-
request.sentCallback = (err) => {
|
|
533
|
-
delete request.sentCallback;
|
|
626
|
+
methodRequest = {
|
|
627
|
+
data: arg,
|
|
628
|
+
method: serviceAndMethod
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
const baseRequest = (serviceRequest || methodRequest);
|
|
632
|
+
const promise = new Promise((resolve, reject) => {
|
|
633
|
+
baseRequest.sentCallback = (err) => {
|
|
634
|
+
delete baseRequest.sentCallback;
|
|
534
635
|
this._outboundSentMessageCount++;
|
|
535
636
|
if (err) {
|
|
536
637
|
reject(err);
|
|
@@ -540,94 +641,24 @@ export class SocketTransport {
|
|
|
540
641
|
};
|
|
541
642
|
});
|
|
542
643
|
this._outboundPreparedMessageCount++;
|
|
644
|
+
const request = Object.assign(baseRequest, { promise });
|
|
543
645
|
this.onTransmit(request);
|
|
544
|
-
return promise;
|
|
646
|
+
return request.promise;
|
|
545
647
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
let method;
|
|
550
|
-
let ackTimeoutMs;
|
|
551
|
-
if (typeof methodOptions === 'object') {
|
|
552
|
-
if (Array.isArray(methodOptions)) {
|
|
553
|
-
service = methodOptions[0];
|
|
554
|
-
serviceMethod = methodOptions[1];
|
|
555
|
-
ackTimeoutMs = methodOptions[2];
|
|
556
|
-
}
|
|
557
|
-
else {
|
|
558
|
-
if ('service' in methodOptions) {
|
|
559
|
-
service = methodOptions.service;
|
|
560
|
-
serviceMethod = methodOptions.method;
|
|
561
|
-
}
|
|
562
|
-
else {
|
|
563
|
-
method = methodOptions.method;
|
|
564
|
-
}
|
|
565
|
-
ackTimeoutMs = methodOptions.ackTimeoutMs;
|
|
566
|
-
}
|
|
648
|
+
triggerAuthenticationEvents(wasSigned, wasAuthenticated) {
|
|
649
|
+
if (!this._signedAuthToken) {
|
|
650
|
+
throw new AuthError('Signed auth token should be set to trigger authentication events');
|
|
567
651
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
cid: this._callIdGenerator(),
|
|
574
|
-
ackTimeoutMs: ackTimeoutMs ?? this.ackTimeoutMs,
|
|
575
|
-
callback: null,
|
|
576
|
-
promise: null
|
|
577
|
-
}, service ? {
|
|
578
|
-
service,
|
|
579
|
-
method: serviceMethod,
|
|
580
|
-
data: arg
|
|
581
|
-
} : {
|
|
582
|
-
method: method,
|
|
583
|
-
data: arg
|
|
584
|
-
});
|
|
585
|
-
let abort;
|
|
586
|
-
const promise = request.promise = new Promise((resolve, reject) => {
|
|
587
|
-
if (request.ackTimeoutMs) {
|
|
588
|
-
request.timeoutId = setTimeout(() => {
|
|
589
|
-
delete callbackMap[request.cid];
|
|
590
|
-
request.callback = null;
|
|
591
|
-
clearTimeout(request.timeoutId);
|
|
592
|
-
delete request.timeoutId;
|
|
593
|
-
reject(new TimeoutError(`Method \'${[service, request.method].filter(Boolean).join('.')}\' timed out.`));
|
|
594
|
-
}, request.ackTimeoutMs);
|
|
652
|
+
this._socket.emit('authStateChange', { authToken: this._authToken, isAuthenticated: true, signedAuthToken: this._signedAuthToken, wasAuthenticated });
|
|
653
|
+
this._socket.emit('authenticate', { authToken: this._authToken, signedAuthToken: this._signedAuthToken, wasSigned });
|
|
654
|
+
for (const plugin of this.plugins) {
|
|
655
|
+
if (plugin.onAuthenticated) {
|
|
656
|
+
plugin.onAuthenticated({ socket: this.socket, transport: this });
|
|
595
657
|
}
|
|
596
|
-
|
|
597
|
-
delete callbackMap[request.cid];
|
|
598
|
-
if (request.timeoutId) {
|
|
599
|
-
clearTimeout(request.timeoutId);
|
|
600
|
-
delete request.timeoutId;
|
|
601
|
-
}
|
|
602
|
-
if (request.callback) {
|
|
603
|
-
request.callback = null;
|
|
604
|
-
reject(new AbortError(`Method \'${[service, request.method].filter(Boolean).join('.')}\' was aborted.`));
|
|
605
|
-
}
|
|
606
|
-
};
|
|
607
|
-
request.callback = (err, result) => {
|
|
608
|
-
delete callbackMap[request.cid];
|
|
609
|
-
request.callback = null;
|
|
610
|
-
if (request.timeoutId) {
|
|
611
|
-
clearTimeout(request.timeoutId);
|
|
612
|
-
delete request.timeoutId;
|
|
613
|
-
}
|
|
614
|
-
if (err) {
|
|
615
|
-
reject(err);
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
resolve(result);
|
|
619
|
-
};
|
|
620
|
-
request.sentCallback = () => {
|
|
621
|
-
delete request.sentCallback;
|
|
622
|
-
this._outboundSentMessageCount++;
|
|
623
|
-
};
|
|
624
|
-
});
|
|
625
|
-
this._outboundPreparedMessageCount++;
|
|
626
|
-
this.onInvoke(request);
|
|
627
|
-
return [promise, abort];
|
|
658
|
+
}
|
|
628
659
|
}
|
|
629
660
|
get url() {
|
|
630
|
-
return this._webSocket
|
|
661
|
+
return this._webSocket?.url || '';
|
|
631
662
|
}
|
|
632
663
|
get webSocket() {
|
|
633
664
|
return this._webSocket;
|
|
@@ -638,17 +669,13 @@ export class SocketTransport {
|
|
|
638
669
|
this._webSocket.onerror = null;
|
|
639
670
|
this._webSocket.onmessage = null;
|
|
640
671
|
this._webSocket.onopen = null;
|
|
641
|
-
delete this.onSocketClose;
|
|
642
|
-
delete this.onSocketError;
|
|
643
|
-
delete this.onSocketMessage;
|
|
644
|
-
delete this.onOpen;
|
|
645
672
|
}
|
|
646
673
|
this._webSocket = value;
|
|
647
|
-
if (
|
|
648
|
-
this._webSocket.onclose = this.onSocketClose
|
|
649
|
-
this._webSocket.onopen = this.onOpen
|
|
650
|
-
this._webSocket.onerror = this.onSocketError
|
|
651
|
-
this._webSocket.onmessage = this.onSocketMessage
|
|
674
|
+
if (this._webSocket) {
|
|
675
|
+
this._webSocket.onclose = this.onSocketClose.bind(this);
|
|
676
|
+
this._webSocket.onopen = this.onOpen.bind(this);
|
|
677
|
+
this._webSocket.onerror = this.onSocketError.bind(this);
|
|
678
|
+
this._webSocket.onmessage = this.onSocketMessage.bind(this);
|
|
652
679
|
}
|
|
653
680
|
}
|
|
654
681
|
}
|