@socket-mesh/server 17.3.6 → 18.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/action.d.ts +38 -41
- package/action.js +18 -22
- package/auth-engine.d.ts +13 -0
- package/auth-engine.js +32 -0
- package/events.d.ts +3 -3
- package/inbound-packet.d.ts +11 -11
- package/index.d.ts +11 -11
- package/index.js +4 -4
- package/middleware-stream.d.ts +3 -3
- package/outbound-packet.d.ts +8 -8
- package/package.json +56 -58
- package/request.d.ts +9 -11
- package/request.js +3 -9
- package/server-options.d.ts +2 -2
- package/server.d.ts +53 -53
- package/server.js +90 -128
- package/serversocket-procedure.d.ts +13 -0
- package/serversocket-procedure.js +9 -0
- package/serversocket.d.ts +23 -22
- package/serversocket.js +663 -737
package/serversocket.js
CHANGED
|
@@ -1,33 +1,18 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
11
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
12
|
-
var m = o[Symbol.asyncIterator], i;
|
|
13
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
14
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
15
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
16
|
-
};
|
|
17
1
|
import cloneDeep from 'clone-deep';
|
|
18
2
|
import { AuthState } from "@socket-mesh/auth";
|
|
19
3
|
import { WritableConsumableStream } from "@socket-mesh/writable-consumable-stream";
|
|
20
4
|
import { AsyncStreamEmitter } from "@socket-mesh/async-stream-emitter";
|
|
21
5
|
import { StreamDemux, StreamDemuxWrapper } from "@socket-mesh/stream-demux";
|
|
22
|
-
import { Request } from "@socket-mesh/request";
|
|
6
|
+
import { Request, RequestWithResponse, createErrorResponse } from "@socket-mesh/request";
|
|
23
7
|
import { dehydrateError, hydrateError, socketProtocolIgnoreStatuses, socketProtocolErrorStatuses, InvalidArgumentsError, SocketProtocolError, TimeoutError, BadConnectionError, InvalidActionError, AuthError, AuthTokenExpiredError, AuthTokenInvalidError, AuthTokenNotBeforeError, AuthTokenError, BrokerError } from "@socket-mesh/errors";
|
|
24
|
-
import { SocketState } from "./socket-state";
|
|
25
|
-
import { MiddlewareType } from "./middleware-type";
|
|
26
|
-
import { ActionAuthenticate, ActionHandshakeSC, ActionInvoke, ActionMessage, ActionPublishIn, ActionPublishOut, ActionSubscribe, ActionTransmit } from "./action";
|
|
27
|
-
import { MiddlewareStream } from './middleware-stream';
|
|
28
|
-
import { isAuthenticatePacket, isHandshakePacket, isPublishPacket, isRemoveAuthTokenPacket, isSubscribePacket, isUnsubscribePacket } from './inbound-packet';
|
|
29
|
-
import { isPublishOutPacket } from './outbound-packet';
|
|
30
|
-
import { AuthenticateRequest, HandshakeRequest, UnsubscribeRequest
|
|
8
|
+
import { SocketState } from "./socket-state.js";
|
|
9
|
+
import { MiddlewareType } from "./middleware-type.js";
|
|
10
|
+
import { ActionAuthenticate, ActionHandshakeSC, ActionInvoke, ActionMessage, ActionPublishIn, ActionPublishOut, ActionSubscribe, ActionTransmit } from "./action.js";
|
|
11
|
+
import { MiddlewareStream } from './middleware-stream.js';
|
|
12
|
+
import { isAuthenticatePacket, isHandshakePacket, isPublishPacket, isRemoveAuthTokenPacket, isSubscribePacket, isUnsubscribePacket } from './inbound-packet.js';
|
|
13
|
+
import { isPublishOutPacket } from './outbound-packet.js';
|
|
14
|
+
import { AuthenticateRequest, HandshakeRequest, UnsubscribeRequest } from './request.js';
|
|
15
|
+
import { ServerSocketProcedure } from './serversocket-procedure.js';
|
|
31
16
|
const HANDSHAKE_REJECTION_STATUS_CODE = 4008;
|
|
32
17
|
export class ServerSocket extends AsyncStreamEmitter {
|
|
33
18
|
constructor(id, server, socket, protocolVersion) {
|
|
@@ -41,7 +26,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
41
26
|
this._receiverDemux = new StreamDemux();
|
|
42
27
|
this.receiver = new StreamDemuxWrapper(this._receiverDemux);
|
|
43
28
|
this._procedureDemux = new StreamDemux();
|
|
44
|
-
this.procedure = new
|
|
29
|
+
this.procedure = new ServerSocketProcedure(this._procedureDemux);
|
|
45
30
|
this.request = this.socket.upgradeReq;
|
|
46
31
|
this.inboundReceivedMessageCount = 0;
|
|
47
32
|
this.inboundProcessedMessageCount = 0;
|
|
@@ -116,7 +101,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
116
101
|
this._handleInboundMessageStream(pongMessage);
|
|
117
102
|
this._handleOutboundPacketStream();
|
|
118
103
|
// Receive incoming raw messages
|
|
119
|
-
this.socket.on('message', (messageBuffer, isBinary) =>
|
|
104
|
+
this.socket.on('message', async (messageBuffer, isBinary) => {
|
|
120
105
|
let message = isBinary ? messageBuffer : messageBuffer.toString();
|
|
121
106
|
this.inboundReceivedMessageCount++;
|
|
122
107
|
let isPong = message === pongMessage;
|
|
@@ -126,7 +111,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
126
111
|
if (this.server.hasMiddleware(MiddlewareType.MIDDLEWARE_INBOUND_RAW)) {
|
|
127
112
|
const action = new ActionMessage(this, message);
|
|
128
113
|
try {
|
|
129
|
-
const { data } =
|
|
114
|
+
const { data } = await this.server._processMiddlewareAction(this.middlewareInboundRawStream, action, this);
|
|
130
115
|
message = data;
|
|
131
116
|
}
|
|
132
117
|
catch (error) {
|
|
@@ -136,20 +121,20 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
136
121
|
}
|
|
137
122
|
this.inboundMessageStream.write(message);
|
|
138
123
|
this.emit('message', { message });
|
|
139
|
-
})
|
|
124
|
+
});
|
|
140
125
|
}
|
|
141
126
|
getBackpressure() {
|
|
142
127
|
return Math.max(this.getInboundBackpressure(), this.getOutboundBackpressure(), this.getListenerBackpressure(), this.receiver.getBackpressure(), this.procedure.getBackpressure());
|
|
143
128
|
}
|
|
144
|
-
|
|
129
|
+
get exchange() {
|
|
130
|
+
return this.server.exchange;
|
|
131
|
+
}
|
|
145
132
|
getInboundBackpressure() {
|
|
146
133
|
return this.inboundReceivedMessageCount - this.inboundProcessedMessageCount;
|
|
147
134
|
}
|
|
148
|
-
;
|
|
149
135
|
getOutboundBackpressure() {
|
|
150
136
|
return this.outboundPreparedMessageCount - this.outboundSentMessageCount;
|
|
151
137
|
}
|
|
152
|
-
;
|
|
153
138
|
_startBatchOnHandshake() {
|
|
154
139
|
this._startBatching();
|
|
155
140
|
setTimeout(() => {
|
|
@@ -158,463 +143,430 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
158
143
|
}
|
|
159
144
|
}, this.batchOnHandshakeDuration);
|
|
160
145
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
let message = _c;
|
|
171
|
-
this.inboundProcessedMessageCount++;
|
|
172
|
-
let isPong = message === pongMessage;
|
|
173
|
-
if (isPong) {
|
|
174
|
-
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
175
|
-
this._destroy(4009);
|
|
176
|
-
this.socket.close(4009);
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
let token = this.getAuthToken();
|
|
180
|
-
if (this.isAuthTokenExpired(token)) {
|
|
181
|
-
this.deauthenticate();
|
|
182
|
-
}
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
let packet;
|
|
186
|
-
try {
|
|
187
|
-
packet = this.decode(message);
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
if (error.name === 'Error') {
|
|
191
|
-
error.name = 'InvalidMessageError';
|
|
192
|
-
}
|
|
193
|
-
this.emitError(error);
|
|
194
|
-
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
195
|
-
this._destroy(4009);
|
|
196
|
-
this.socket.close(4009);
|
|
197
|
-
}
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
if (Array.isArray(packet)) {
|
|
201
|
-
let len = packet.length;
|
|
202
|
-
for (let i = 0; i < len; i++) {
|
|
203
|
-
yield this._processInboundPacket(packet[i], message);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
yield this._processInboundPacket(packet, message);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
finally {
|
|
211
|
-
_d = true;
|
|
212
|
-
}
|
|
146
|
+
async _handleInboundMessageStream(pongMessage) {
|
|
147
|
+
for await (let message of this.inboundMessageStream) {
|
|
148
|
+
this.inboundProcessedMessageCount++;
|
|
149
|
+
let isPong = message === pongMessage;
|
|
150
|
+
if (isPong) {
|
|
151
|
+
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
152
|
+
this._destroy(4009);
|
|
153
|
+
this.socket.close(4009);
|
|
154
|
+
continue;
|
|
213
155
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
try {
|
|
218
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
156
|
+
let token = this.getAuthToken();
|
|
157
|
+
if (this.isAuthTokenExpired(token)) {
|
|
158
|
+
this.deauthenticate();
|
|
219
159
|
}
|
|
220
|
-
|
|
160
|
+
continue;
|
|
221
161
|
}
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
;
|
|
225
|
-
_handleHandshakeTimeout() {
|
|
226
|
-
this.disconnect(4005);
|
|
227
|
-
}
|
|
228
|
-
;
|
|
229
|
-
_processHandshakeRequest(request) {
|
|
230
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
231
|
-
let data = request.data || { authToken: '' };
|
|
232
|
-
let signedAuthToken = data.authToken;
|
|
233
|
-
clearTimeout(this._handshakeTimeoutRef);
|
|
234
|
-
const authInfo = yield this._validateAuthToken(signedAuthToken);
|
|
235
|
-
const action = new ActionHandshakeSC(this, request, authInfo);
|
|
162
|
+
let packet;
|
|
236
163
|
try {
|
|
237
|
-
|
|
164
|
+
packet = this.decode(message);
|
|
238
165
|
}
|
|
239
166
|
catch (error) {
|
|
240
|
-
if (error.
|
|
241
|
-
error.
|
|
167
|
+
if (error.name === 'Error') {
|
|
168
|
+
error.name = 'InvalidMessageError';
|
|
242
169
|
}
|
|
243
|
-
|
|
244
|
-
this.
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const oldAuthState = this.authState;
|
|
248
|
-
let authError = undefined;
|
|
249
|
-
try {
|
|
250
|
-
yield this._processAuthentication(authInfo);
|
|
251
|
-
if (this.state === SocketState.CLOSED) {
|
|
252
|
-
return;
|
|
170
|
+
this.emitError(error);
|
|
171
|
+
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
172
|
+
this._destroy(4009);
|
|
173
|
+
this.socket.close(4009);
|
|
253
174
|
}
|
|
175
|
+
continue;
|
|
254
176
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
authError = dehydrateError(error);
|
|
260
|
-
if (error.isBadToken) {
|
|
261
|
-
this.deauthenticate();
|
|
262
|
-
}
|
|
177
|
+
if (Array.isArray(packet)) {
|
|
178
|
+
let len = packet.length;
|
|
179
|
+
for (let i = 0; i < len; i++) {
|
|
180
|
+
await this._processInboundPacket(packet[i], message);
|
|
263
181
|
}
|
|
264
182
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
pingTimeout: this.server.pingTimeout,
|
|
268
|
-
isAuthenticated: !!this.authToken,
|
|
269
|
-
authError: authError
|
|
270
|
-
};
|
|
271
|
-
const serverSocketStatus = {
|
|
272
|
-
id: this.id,
|
|
273
|
-
pingTimeout: this.server.pingTimeout,
|
|
274
|
-
isAuthenticated: !!this.authToken,
|
|
275
|
-
authError: authError
|
|
276
|
-
};
|
|
277
|
-
if (this.server.pendingClients[this.id]) {
|
|
278
|
-
delete this.server.pendingClients[this.id];
|
|
279
|
-
this.server.pendingClientsCount--;
|
|
280
|
-
}
|
|
281
|
-
this.server.clients[this.id] = this;
|
|
282
|
-
this.server.clientsCount++;
|
|
283
|
-
this.state = SocketState.OPEN;
|
|
284
|
-
if (clientSocketStatus.isAuthenticated) {
|
|
285
|
-
// Needs to be executed after the connection event to allow
|
|
286
|
-
// consumers to be setup from inside the connection loop.
|
|
287
|
-
(() => __awaiter(this, void 0, void 0, function* () {
|
|
288
|
-
yield this.listen('connect').once();
|
|
289
|
-
this.triggerAuthenticationEvents(oldAuthState);
|
|
290
|
-
}))();
|
|
291
|
-
}
|
|
292
|
-
// Treat authentication failure as a 'soft' error
|
|
293
|
-
request.end(clientSocketStatus);
|
|
294
|
-
if (this.batchOnHandshake) {
|
|
295
|
-
this._startBatchOnHandshake();
|
|
183
|
+
else {
|
|
184
|
+
await this._processInboundPacket(packet, message);
|
|
296
185
|
}
|
|
297
|
-
|
|
298
|
-
this.server.emit('connection', Object.assign({ socket: this }, serverSocketStatus));
|
|
299
|
-
this.middlewareHandshakeStream.close();
|
|
300
|
-
});
|
|
186
|
+
}
|
|
301
187
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
188
|
+
_handleHandshakeTimeout() {
|
|
189
|
+
this.disconnect(4005);
|
|
190
|
+
}
|
|
191
|
+
async _processHandshakeRequest(request) {
|
|
192
|
+
let data = request.data || { authToken: '' };
|
|
193
|
+
let signedAuthToken = data.authToken;
|
|
194
|
+
clearTimeout(this._handshakeTimeoutRef);
|
|
195
|
+
const authInfo = await this._validateAuthToken(signedAuthToken);
|
|
196
|
+
const action = new ActionHandshakeSC(this, request, authInfo);
|
|
197
|
+
try {
|
|
198
|
+
await this.server._processMiddlewareAction(this.middlewareHandshakeStream, action);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
if (error.statusCode == null) {
|
|
202
|
+
error.statusCode = HANDSHAKE_REJECTION_STATUS_CODE;
|
|
309
203
|
}
|
|
310
|
-
|
|
311
|
-
|
|
204
|
+
request.error(error);
|
|
205
|
+
this.disconnect(error.statusCode);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const oldAuthState = this.authState;
|
|
209
|
+
let authError = undefined;
|
|
210
|
+
try {
|
|
211
|
+
await this._processAuthentication(authInfo);
|
|
212
|
+
if (this.state === SocketState.CLOSED) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
if (signedAuthToken != null) {
|
|
218
|
+
// Because the token is optional as part of the handshake, we don't count
|
|
219
|
+
// it as an error if the token wasn't provided.
|
|
220
|
+
authError = dehydrateError(error);
|
|
221
|
+
if (error.isBadToken) {
|
|
312
222
|
this.deauthenticate();
|
|
313
|
-
request.error(error);
|
|
314
|
-
return;
|
|
315
223
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const clientSocketStatus = {
|
|
227
|
+
id: this.id,
|
|
228
|
+
pingTimeout: this.server.pingTimeout,
|
|
229
|
+
isAuthenticated: !!this.authToken,
|
|
230
|
+
authError: authError
|
|
231
|
+
};
|
|
232
|
+
const serverSocketStatus = {
|
|
233
|
+
id: this.id,
|
|
234
|
+
pingTimeout: this.server.pingTimeout,
|
|
235
|
+
isAuthenticated: !!this.authToken,
|
|
236
|
+
authError: authError
|
|
237
|
+
};
|
|
238
|
+
if (this.server.pendingClients[this.id]) {
|
|
239
|
+
delete this.server.pendingClients[this.id];
|
|
240
|
+
this.server.pendingClientsCount--;
|
|
241
|
+
}
|
|
242
|
+
this.server.clients[this.id] = this;
|
|
243
|
+
this.server.clientsCount++;
|
|
244
|
+
this.state = SocketState.OPEN;
|
|
245
|
+
if (clientSocketStatus.isAuthenticated) {
|
|
246
|
+
// Needs to be executed after the connection event to allow
|
|
247
|
+
// consumers to be setup from inside the connection loop.
|
|
248
|
+
(async () => {
|
|
249
|
+
await this.listen('connect').once();
|
|
250
|
+
this.triggerAuthenticationEvents(oldAuthState);
|
|
251
|
+
})();
|
|
252
|
+
}
|
|
253
|
+
// Treat authentication failure as a 'soft' error
|
|
254
|
+
request.end(clientSocketStatus);
|
|
255
|
+
if (this.batchOnHandshake) {
|
|
256
|
+
this._startBatchOnHandshake();
|
|
257
|
+
}
|
|
258
|
+
this.emit('connect', serverSocketStatus);
|
|
259
|
+
this.server.emit('connection', { socket: this, ...serverSocketStatus });
|
|
260
|
+
this.middlewareHandshakeStream.close();
|
|
261
|
+
}
|
|
262
|
+
async _processAuthenticateRequest(request) {
|
|
263
|
+
let signedAuthToken = request.data;
|
|
264
|
+
let oldAuthState = this.authState;
|
|
265
|
+
let authInfo = await this._validateAuthToken(signedAuthToken);
|
|
266
|
+
try {
|
|
267
|
+
await this._processAuthentication(authInfo);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
if (error instanceof AuthTokenError) {
|
|
271
|
+
this.deauthenticate();
|
|
272
|
+
request.error(error);
|
|
320
273
|
return;
|
|
321
274
|
}
|
|
322
|
-
this.triggerAuthenticationEvents(oldAuthState);
|
|
323
275
|
request.end({
|
|
324
276
|
isAuthenticated: !!this.authToken,
|
|
325
|
-
authError: null
|
|
277
|
+
authError: signedAuthToken == null ? null : dehydrateError(error)
|
|
326
278
|
});
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
this.triggerAuthenticationEvents(oldAuthState);
|
|
282
|
+
request.end({
|
|
283
|
+
isAuthenticated: !!this.authToken,
|
|
284
|
+
authError: null
|
|
327
285
|
});
|
|
328
286
|
}
|
|
329
|
-
_subscribeSocket(channelName, subscriptionOptions) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
channel: channelName,
|
|
357
|
-
subscriptionOptions
|
|
358
|
-
});
|
|
359
|
-
this.server.emit('subscription', {
|
|
360
|
-
socket: this,
|
|
361
|
-
channel: channelName,
|
|
362
|
-
subscriptionOptions
|
|
363
|
-
});
|
|
287
|
+
async _subscribeSocket(channelName, subscriptionOptions) {
|
|
288
|
+
if (this.server.socketChannelLimit && this.channelSubscriptionsCount >= this.server.socketChannelLimit) {
|
|
289
|
+
throw new InvalidActionError(`Socket ${this.id} tried to exceed the channel subscription limit of ${this.server.socketChannelLimit}`);
|
|
290
|
+
}
|
|
291
|
+
if (this.channelSubscriptionsCount == null) {
|
|
292
|
+
this.channelSubscriptionsCount = 0;
|
|
293
|
+
}
|
|
294
|
+
if (this.channelSubscriptions[channelName] == null) {
|
|
295
|
+
this.channelSubscriptions[channelName] = true;
|
|
296
|
+
this.channelSubscriptionsCount++;
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
this.server.brokerEngine.subscribeSocket(this, channelName);
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
delete this.channelSubscriptions[channelName];
|
|
303
|
+
this.channelSubscriptionsCount--;
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
this.emit('subscribe', {
|
|
307
|
+
channel: channelName,
|
|
308
|
+
subscriptionOptions
|
|
309
|
+
});
|
|
310
|
+
this.server.emit('subscription', {
|
|
311
|
+
socket: this,
|
|
312
|
+
channel: channelName,
|
|
313
|
+
subscriptionOptions
|
|
364
314
|
});
|
|
365
315
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
316
|
+
async _processSubscribeRequest(request) {
|
|
317
|
+
if (this.state === SocketState.OPEN) {
|
|
369
318
|
let subscriptionOptions = Object.assign({}, request.data);
|
|
370
319
|
let channelName = subscriptionOptions.channel;
|
|
371
320
|
delete subscriptionOptions.channel;
|
|
372
|
-
if (this.state === SocketState.OPEN) {
|
|
373
|
-
try {
|
|
374
|
-
yield this._subscribeSocket(channelName, subscriptionOptions);
|
|
375
|
-
}
|
|
376
|
-
catch (err) {
|
|
377
|
-
let error = new BrokerError(`Failed to subscribe socket to the ${channelName} channel - ${err}`);
|
|
378
|
-
this.emitError(error);
|
|
379
|
-
request.error(error);
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
request.end();
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
// This is an invalid state; it means the client tried to subscribe before
|
|
386
|
-
// having completed the handshake.
|
|
387
|
-
let error = new InvalidActionError('Cannot subscribe socket to a channel before it has completed the handshake');
|
|
388
|
-
this.emitError(error);
|
|
389
|
-
request.error(error);
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
_unsubscribeFromAllChannels() {
|
|
393
|
-
const channels = Object.keys(this.channelSubscriptions);
|
|
394
|
-
return Promise.all(channels.map((channel) => this._unsubscribe(channel)));
|
|
395
|
-
}
|
|
396
|
-
;
|
|
397
|
-
_unsubscribe(channel) {
|
|
398
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
399
|
-
if (typeof channel !== 'string') {
|
|
400
|
-
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from an invalid channel name`);
|
|
401
|
-
}
|
|
402
|
-
if (!this.channelSubscriptions[channel]) {
|
|
403
|
-
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from a channel which it is not subscribed to`);
|
|
404
|
-
}
|
|
405
321
|
try {
|
|
406
|
-
|
|
407
|
-
delete this.channelSubscriptions[channel];
|
|
408
|
-
if (this.channelSubscriptionsCount != null) {
|
|
409
|
-
this.channelSubscriptionsCount--;
|
|
410
|
-
}
|
|
411
|
-
this.emit('unsubscribe', { channel });
|
|
412
|
-
this.server.emit('unsubscription', { socket: this, channel });
|
|
322
|
+
await this._subscribeSocket(channelName, subscriptionOptions);
|
|
413
323
|
}
|
|
414
324
|
catch (err) {
|
|
415
|
-
|
|
416
|
-
this.emitError(error);
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
;
|
|
421
|
-
_processUnsubscribePacket(packet) {
|
|
422
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
423
|
-
let channel = packet.data;
|
|
424
|
-
try {
|
|
425
|
-
yield this._unsubscribe(channel);
|
|
426
|
-
}
|
|
427
|
-
catch (err) {
|
|
428
|
-
let error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
429
|
-
this.emitError(error);
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
;
|
|
434
|
-
_processUnsubscribeRequest(request) {
|
|
435
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
436
|
-
const channel = request.data;
|
|
437
|
-
try {
|
|
438
|
-
yield this._unsubscribe(channel);
|
|
439
|
-
}
|
|
440
|
-
catch (err) {
|
|
441
|
-
let error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
325
|
+
let error = new BrokerError(`Failed to subscribe socket to the ${channelName} channel - ${err}`);
|
|
442
326
|
this.emitError(error);
|
|
443
327
|
request.error(error);
|
|
444
328
|
return;
|
|
445
329
|
}
|
|
446
330
|
request.end();
|
|
447
|
-
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
// This is an invalid state; it means the client tried to subscribe before
|
|
334
|
+
// having completed the handshake.
|
|
335
|
+
let error = new InvalidActionError('Cannot subscribe socket to a channel before it has completed the handshake');
|
|
336
|
+
this.emitError(error);
|
|
337
|
+
request.error(error);
|
|
448
338
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
339
|
+
async _unsubscribeFromAllChannels() {
|
|
340
|
+
const channels = Object.keys(this.channelSubscriptions);
|
|
341
|
+
await Promise.all(channels.map((channel) => this._unsubscribe(channel)));
|
|
342
|
+
}
|
|
343
|
+
async _unsubscribe(channel) {
|
|
344
|
+
if (typeof channel !== 'string') {
|
|
345
|
+
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from an invalid channel name`);
|
|
346
|
+
}
|
|
347
|
+
if (!this.channelSubscriptions[channel]) {
|
|
348
|
+
throw new InvalidActionError(`Socket ${this.id} tried to unsubscribe from a channel which it is not subscribed to`);
|
|
349
|
+
}
|
|
350
|
+
try {
|
|
351
|
+
await this.server.brokerEngine.unsubscribeSocket(this, channel);
|
|
352
|
+
delete this.channelSubscriptions[channel];
|
|
353
|
+
if (this.channelSubscriptionsCount != null) {
|
|
354
|
+
this.channelSubscriptionsCount--;
|
|
462
355
|
}
|
|
463
|
-
|
|
356
|
+
this.emit('unsubscribe', { channel });
|
|
357
|
+
this.server.emit('unsubscription', { socket: this, channel });
|
|
358
|
+
}
|
|
359
|
+
catch (err) {
|
|
360
|
+
const error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
361
|
+
this.emitError(error);
|
|
362
|
+
}
|
|
464
363
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
364
|
+
async _processUnsubscribePacket(packet) {
|
|
365
|
+
let channel = packet.data;
|
|
366
|
+
try {
|
|
367
|
+
await this._unsubscribe(channel);
|
|
368
|
+
}
|
|
369
|
+
catch (err) {
|
|
370
|
+
let error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
371
|
+
this.emitError(error);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
async _processUnsubscribeRequest(request) {
|
|
375
|
+
const channel = request.data;
|
|
376
|
+
try {
|
|
377
|
+
await this._unsubscribe(channel);
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
let error = new BrokerError(`Failed to unsubscribe socket from the ${channel} channel - ${err}`);
|
|
381
|
+
this.emitError(error);
|
|
382
|
+
request.error(error);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
request.end();
|
|
386
|
+
}
|
|
387
|
+
async _processInboundPublishPacket(packet) {
|
|
388
|
+
try {
|
|
389
|
+
await this.server.exchange.invokePublish(packet.data.channel, packet.data.data);
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
this.emitError(error);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
async _processInboundPublishRequest(request) {
|
|
396
|
+
try {
|
|
397
|
+
await this.server.exchange.invokePublish(request.data.channel, request.data.data);
|
|
398
|
+
}
|
|
399
|
+
catch (error) {
|
|
400
|
+
this.emitError(error);
|
|
401
|
+
request.error(error);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
request.end();
|
|
405
|
+
}
|
|
406
|
+
async _processInboundPacket(packet, message) {
|
|
407
|
+
if (packet && typeof packet.event === 'string') {
|
|
408
|
+
let isRPC = ('cid' in packet) && typeof packet.cid === 'number';
|
|
409
|
+
if (isHandshakePacket(packet)) {
|
|
410
|
+
if (!isRPC) {
|
|
411
|
+
let error = new InvalidActionError('Handshake request was malformatted');
|
|
412
|
+
this.emitError(error);
|
|
413
|
+
this._destroy(HANDSHAKE_REJECTION_STATUS_CODE);
|
|
414
|
+
this.socket.close(HANDSHAKE_REJECTION_STATUS_CODE);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const request = new HandshakeRequest(this, packet.cid, packet.event, packet.data);
|
|
418
|
+
await this._processHandshakeRequest(request);
|
|
419
|
+
this._procedureDemux.write(request.procedure, request);
|
|
472
420
|
return;
|
|
473
421
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
catch (error) {
|
|
478
|
-
this.emitError(error);
|
|
479
|
-
request.error(error);
|
|
422
|
+
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
423
|
+
this._destroy(4009);
|
|
424
|
+
this.socket.close(4009);
|
|
480
425
|
return;
|
|
481
426
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
let isRPC = ('cid' in packet);
|
|
489
|
-
if (isHandshakePacket(packet)) {
|
|
490
|
-
const request = new HandshakeRequest(this, packet.cid, packet.event, packet.data);
|
|
491
|
-
yield this._processHandshakeRequest(request);
|
|
492
|
-
this._procedureDemux.write(request.procedure, request);
|
|
427
|
+
if (isAuthenticatePacket(packet)) {
|
|
428
|
+
if (!isRPC) {
|
|
429
|
+
let error = new InvalidActionError('Authenticate request was malformatted');
|
|
430
|
+
this.emitError(error);
|
|
431
|
+
this._destroy(HANDSHAKE_REJECTION_STATUS_CODE);
|
|
432
|
+
this.socket.close(HANDSHAKE_REJECTION_STATUS_CODE);
|
|
493
433
|
return;
|
|
494
434
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
435
|
+
// Let AGServer handle these events.
|
|
436
|
+
const request = new AuthenticateRequest(this, packet.cid, packet.event, packet.data);
|
|
437
|
+
await this._processAuthenticateRequest(request);
|
|
438
|
+
this._procedureDemux.write(request.procedure, request);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
if (isRemoveAuthTokenPacket(packet)) {
|
|
442
|
+
this.deauthenticateSelf();
|
|
443
|
+
this._receiverDemux.write(packet.event, packet.data);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
if (isUnsubscribePacket(packet)) {
|
|
447
|
+
if (typeof packet.data !== 'string') {
|
|
448
|
+
const error = new InvalidActionError('Unsubscribe channel name was malformatted');
|
|
449
|
+
this.emitError(error);
|
|
450
|
+
if (isRPC) {
|
|
451
|
+
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
452
|
+
request.error(error);
|
|
453
|
+
}
|
|
498
454
|
return;
|
|
499
455
|
}
|
|
500
|
-
if (
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
yield this._processAuthenticateRequest(request);
|
|
456
|
+
if (isRPC) {
|
|
457
|
+
const request = new UnsubscribeRequest(this, packet.cid, packet.event, packet.data);
|
|
458
|
+
await this._processUnsubscribeRequest(request);
|
|
504
459
|
this._procedureDemux.write(request.procedure, request);
|
|
505
460
|
return;
|
|
506
461
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
462
|
+
await this._processUnsubscribePacket(packet);
|
|
463
|
+
this._receiverDemux.write(packet.event, packet.data);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
let action;
|
|
467
|
+
if (isPublishPacket(packet)) {
|
|
468
|
+
if (!this.server.allowClientPublish) {
|
|
469
|
+
let error = new InvalidActionError('Client publish feature is disabled');
|
|
470
|
+
this.emitError(error);
|
|
513
471
|
if (isRPC) {
|
|
514
|
-
const request = new
|
|
515
|
-
|
|
516
|
-
this._procedureDemux.write(request.procedure, request);
|
|
517
|
-
return;
|
|
472
|
+
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
473
|
+
request.error(error);
|
|
518
474
|
}
|
|
519
|
-
yield this._processUnsubscribePacket(packet);
|
|
520
|
-
this._receiverDemux.write(packet.event, packet.data);
|
|
521
475
|
return;
|
|
522
476
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
this.
|
|
528
|
-
|
|
529
|
-
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
530
|
-
request.error(error);
|
|
531
|
-
}
|
|
532
|
-
return;
|
|
477
|
+
if (!packet.data || typeof packet.data.channel !== 'string') {
|
|
478
|
+
const error = new InvalidActionError('Publish channel name was malformatted');
|
|
479
|
+
this.emitError(error);
|
|
480
|
+
if (isRPC) {
|
|
481
|
+
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
482
|
+
request.error(error);
|
|
533
483
|
}
|
|
534
|
-
|
|
535
|
-
}
|
|
536
|
-
else if (isSubscribePacket(packet)) {
|
|
537
|
-
action = new ActionSubscribe(this, packet.data);
|
|
538
|
-
}
|
|
539
|
-
else if (isRPC) {
|
|
540
|
-
action = new ActionInvoke(this, packet.event, packet.data);
|
|
541
|
-
}
|
|
542
|
-
else {
|
|
543
|
-
action = new ActionTransmit(this, packet.event, packet.data);
|
|
544
|
-
}
|
|
545
|
-
const tokenExpiredError = this._processAuthTokenExpiry();
|
|
546
|
-
if (tokenExpiredError) {
|
|
547
|
-
action.authTokenExpiredError = tokenExpiredError;
|
|
484
|
+
return;
|
|
548
485
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
486
|
+
action = new ActionPublishIn(this, packet.data);
|
|
487
|
+
}
|
|
488
|
+
else if (isSubscribePacket(packet)) {
|
|
489
|
+
if (!packet.data || typeof packet.data.channel !== 'string') {
|
|
490
|
+
const error = new InvalidActionError('Subscribe channel name was malformatted');
|
|
491
|
+
this.emitError(error);
|
|
492
|
+
if (isRPC) {
|
|
493
|
+
const request = new Request(this, packet.cid, packet.event, packet.data);
|
|
557
494
|
request.error(error);
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
if (isSubscribeRequest(request)) {
|
|
561
|
-
if (!request.data) {
|
|
562
|
-
request.data = {};
|
|
563
|
-
}
|
|
564
|
-
request.data.data = newData;
|
|
565
|
-
yield this._processSubscribeRequest(request);
|
|
566
495
|
}
|
|
567
|
-
else if (isPublishRequest(request)) {
|
|
568
|
-
if (!request.data) {
|
|
569
|
-
request.data = {};
|
|
570
|
-
}
|
|
571
|
-
request.data.data = newData;
|
|
572
|
-
yield this._processInboundPublishRequest(request);
|
|
573
|
-
}
|
|
574
|
-
else {
|
|
575
|
-
request.data = newData;
|
|
576
|
-
}
|
|
577
|
-
this._procedureDemux.write(request.procedure, request);
|
|
578
496
|
return;
|
|
579
497
|
}
|
|
498
|
+
action = new ActionSubscribe(this, packet.data);
|
|
499
|
+
}
|
|
500
|
+
else if (isRPC) {
|
|
501
|
+
action = new ActionInvoke(this, packet.event, packet.data);
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
action = new ActionTransmit(this, packet.event, packet.data);
|
|
505
|
+
}
|
|
506
|
+
const tokenExpiredError = this._processAuthTokenExpiry();
|
|
507
|
+
if (tokenExpiredError) {
|
|
508
|
+
action.authTokenExpiredError = tokenExpiredError;
|
|
509
|
+
}
|
|
510
|
+
let newData;
|
|
511
|
+
if (isRPC) {
|
|
580
512
|
try {
|
|
581
|
-
let { data } =
|
|
513
|
+
let { data } = await this.server._processMiddlewareAction(this.middlewareInboundStream, action, this);
|
|
582
514
|
newData = data;
|
|
583
515
|
}
|
|
584
516
|
catch (error) {
|
|
517
|
+
this.sendObject(createErrorResponse(packet.cid, error));
|
|
585
518
|
return;
|
|
586
519
|
}
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
520
|
+
let request;
|
|
521
|
+
if (isSubscribePacket(packet) || isPublishPacket(packet)) {
|
|
522
|
+
request = new Request(this, packet.cid, packet.event, packet.data);
|
|
523
|
+
request.data.data = newData;
|
|
524
|
+
if (isSubscribePacket(packet)) {
|
|
525
|
+
await this._processSubscribeRequest(request);
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
await this._processInboundPublishRequest(request);
|
|
590
529
|
}
|
|
591
|
-
packet.data.data = newData;
|
|
592
|
-
yield this._processInboundPublishPacket(packet);
|
|
593
530
|
}
|
|
594
|
-
|
|
531
|
+
else {
|
|
532
|
+
request = new RequestWithResponse(this, packet.cid, packet.event, newData);
|
|
533
|
+
}
|
|
534
|
+
this._procedureDemux.write(request.procedure, request);
|
|
595
535
|
return;
|
|
596
536
|
}
|
|
597
|
-
|
|
598
|
-
this.
|
|
599
|
-
|
|
600
|
-
return;
|
|
537
|
+
try {
|
|
538
|
+
let { data } = await this.server._processMiddlewareAction(this.middlewareInboundStream, action, this);
|
|
539
|
+
newData = data;
|
|
601
540
|
}
|
|
602
|
-
|
|
603
|
-
// If incoming message is a response to a previously sent message
|
|
604
|
-
const ret = this._callbackMap[packet.rid];
|
|
605
|
-
if (ret) {
|
|
606
|
-
clearTimeout(ret.timeout);
|
|
607
|
-
delete this._callbackMap[packet.rid];
|
|
608
|
-
const rehydratedError = hydrateError(packet.error);
|
|
609
|
-
ret.callback(rehydratedError, packet.data);
|
|
610
|
-
}
|
|
541
|
+
catch (error) {
|
|
611
542
|
return;
|
|
612
543
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
544
|
+
if (isPublishPacket(packet)) {
|
|
545
|
+
packet.data.data = newData;
|
|
546
|
+
await this._processInboundPublishPacket(packet);
|
|
547
|
+
}
|
|
548
|
+
this._receiverDemux.write(packet.event, newData);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
if (this.server.strictHandshake && this.state === SocketState.CONNECTING) {
|
|
552
|
+
this._destroy(4009);
|
|
553
|
+
this.socket.close(4009);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (packet && 'rid' in packet && typeof packet.rid === 'number') {
|
|
557
|
+
// If incoming message is a response to a previously sent message
|
|
558
|
+
const ret = this._callbackMap[packet.rid];
|
|
559
|
+
if (ret) {
|
|
560
|
+
clearTimeout(ret.timeout);
|
|
561
|
+
delete this._callbackMap[packet.rid];
|
|
562
|
+
const rehydratedError = hydrateError(packet.error);
|
|
563
|
+
ret.callback(rehydratedError, packet.data);
|
|
564
|
+
}
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
// The last remaining case is to treat the message as raw
|
|
568
|
+
this.emit('raw', { message });
|
|
616
569
|
}
|
|
617
|
-
;
|
|
618
570
|
_resetPongTimeout() {
|
|
619
571
|
if (this.server.pingTimeoutDisabled) {
|
|
620
572
|
return;
|
|
@@ -644,7 +596,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
644
596
|
delete this._callbackMap[i];
|
|
645
597
|
clearTimeout(eventObject.timeout);
|
|
646
598
|
delete eventObject.timeout;
|
|
647
|
-
const errorMessage = `Event
|
|
599
|
+
const errorMessage = `Event ${eventObject.event} was aborted due to a bad connection`;
|
|
648
600
|
const badConnectionError = new BadConnectionError(errorMessage, failureType);
|
|
649
601
|
const callback = eventObject.callback;
|
|
650
602
|
delete eventObject.callback;
|
|
@@ -697,71 +649,69 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
697
649
|
this.procedure.kill();
|
|
698
650
|
this.killListeners();
|
|
699
651
|
}
|
|
700
|
-
_destroy(code, reason) {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
652
|
+
async _destroy(code, reason) {
|
|
653
|
+
clearInterval(this._pingIntervalTicker);
|
|
654
|
+
clearTimeout(this._pingTimeoutTicker);
|
|
655
|
+
this._cancelBatching();
|
|
656
|
+
if (this.state === SocketState.CLOSED) {
|
|
657
|
+
this._abortAllPendingEventsDueToBadConnection('connectAbort');
|
|
658
|
+
}
|
|
659
|
+
else {
|
|
660
|
+
if (!reason) {
|
|
661
|
+
reason = socketProtocolErrorStatuses[code];
|
|
662
|
+
}
|
|
663
|
+
const prevState = this.state;
|
|
664
|
+
this.state = SocketState.CLOSED;
|
|
665
|
+
if (prevState === SocketState.CONNECTING) {
|
|
706
666
|
this._abortAllPendingEventsDueToBadConnection('connectAbort');
|
|
667
|
+
this.emit('connectAbort', { code, reason });
|
|
668
|
+
this.server.emit('connectionAbort', { socket: this, code, reason });
|
|
707
669
|
}
|
|
708
670
|
else {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
671
|
+
this._abortAllPendingEventsDueToBadConnection('disconnect');
|
|
672
|
+
this.emit('disconnect', { code, reason });
|
|
673
|
+
this.server.emit('disconnection', { socket: this, code, reason });
|
|
674
|
+
}
|
|
675
|
+
this.emit('close', { code, reason });
|
|
676
|
+
this.server.emit('closure', { socket: this, code, reason });
|
|
677
|
+
clearTimeout(this._handshakeTimeoutRef);
|
|
678
|
+
let isClientFullyConnected = !!this.server.clients[this.id];
|
|
679
|
+
if (isClientFullyConnected) {
|
|
680
|
+
delete this.server.clients[this.id];
|
|
681
|
+
this.server.clientsCount--;
|
|
682
|
+
}
|
|
683
|
+
let isClientPending = !!this.server.pendingClients[this.id];
|
|
684
|
+
if (isClientPending) {
|
|
685
|
+
delete this.server.pendingClients[this.id];
|
|
686
|
+
this.server.pendingClientsCount--;
|
|
687
|
+
}
|
|
688
|
+
if (!socketProtocolIgnoreStatuses[code]) {
|
|
689
|
+
let closeMessage;
|
|
690
|
+
if (typeof reason === 'string') {
|
|
691
|
+
closeMessage = `Socket connection closed with status code ${code} and reason: ${reason}`;
|
|
718
692
|
}
|
|
719
693
|
else {
|
|
720
|
-
|
|
721
|
-
this.emit('disconnect', { code, reason });
|
|
722
|
-
this.server.emit('disconnection', { socket: this, code, reason });
|
|
723
|
-
}
|
|
724
|
-
this.emit('close', { code, reason });
|
|
725
|
-
this.server.emit('closure', { socket: this, code, reason });
|
|
726
|
-
clearTimeout(this._handshakeTimeoutRef);
|
|
727
|
-
let isClientFullyConnected = !!this.server.clients[this.id];
|
|
728
|
-
if (isClientFullyConnected) {
|
|
729
|
-
delete this.server.clients[this.id];
|
|
730
|
-
this.server.clientsCount--;
|
|
731
|
-
}
|
|
732
|
-
let isClientPending = !!this.server.pendingClients[this.id];
|
|
733
|
-
if (isClientPending) {
|
|
734
|
-
delete this.server.pendingClients[this.id];
|
|
735
|
-
this.server.pendingClientsCount--;
|
|
694
|
+
closeMessage = `Socket connection closed with status code ${code}`;
|
|
736
695
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
if (reason) {
|
|
740
|
-
closeMessage = `Socket connection closed with status code ${code} and reason: ${reason}`;
|
|
741
|
-
}
|
|
742
|
-
else {
|
|
743
|
-
closeMessage = `Socket connection closed with status code ${code}`;
|
|
744
|
-
}
|
|
745
|
-
let err = new SocketProtocolError(socketProtocolErrorStatuses[code] || closeMessage, code);
|
|
746
|
-
this.emitError(err);
|
|
747
|
-
}
|
|
748
|
-
yield this._unsubscribeFromAllChannels();
|
|
749
|
-
let cleanupMode = this.server.options.socketStreamCleanupMode;
|
|
750
|
-
if (cleanupMode === 'kill') {
|
|
751
|
-
(() => __awaiter(this, void 0, void 0, function* () {
|
|
752
|
-
yield this.listen('end').once();
|
|
753
|
-
this.killAllStreams();
|
|
754
|
-
}))();
|
|
755
|
-
}
|
|
756
|
-
else if (cleanupMode === 'close') {
|
|
757
|
-
(() => __awaiter(this, void 0, void 0, function* () {
|
|
758
|
-
yield this.listen('end').once();
|
|
759
|
-
this.closeAllStreams();
|
|
760
|
-
}))();
|
|
761
|
-
}
|
|
762
|
-
this.emit('end');
|
|
696
|
+
let err = new SocketProtocolError(socketProtocolErrorStatuses[code] || closeMessage, code);
|
|
697
|
+
this.emitError(err);
|
|
763
698
|
}
|
|
764
|
-
|
|
699
|
+
await this._unsubscribeFromAllChannels();
|
|
700
|
+
let cleanupMode = this.server.options.socketStreamCleanupMode;
|
|
701
|
+
if (cleanupMode === 'kill') {
|
|
702
|
+
(async () => {
|
|
703
|
+
await this.listen('end').once();
|
|
704
|
+
this.killAllStreams();
|
|
705
|
+
})();
|
|
706
|
+
}
|
|
707
|
+
else if (cleanupMode === 'close') {
|
|
708
|
+
(async () => {
|
|
709
|
+
await this.listen('end').once();
|
|
710
|
+
this.closeAllStreams();
|
|
711
|
+
})();
|
|
712
|
+
}
|
|
713
|
+
this.emit('end');
|
|
714
|
+
}
|
|
765
715
|
}
|
|
766
716
|
disconnect(code, reason) {
|
|
767
717
|
code = code || 1000;
|
|
@@ -850,7 +800,6 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
850
800
|
this.isBatching = false;
|
|
851
801
|
this._cancelBatching();
|
|
852
802
|
}
|
|
853
|
-
;
|
|
854
803
|
serializeObject(object) {
|
|
855
804
|
let str;
|
|
856
805
|
try {
|
|
@@ -862,7 +811,6 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
862
811
|
}
|
|
863
812
|
return str;
|
|
864
813
|
}
|
|
865
|
-
;
|
|
866
814
|
sendObject(object) {
|
|
867
815
|
if (this.isBufferingBatch) {
|
|
868
816
|
this._batchBuffer.push(object);
|
|
@@ -873,47 +821,27 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
873
821
|
this.send(str);
|
|
874
822
|
}
|
|
875
823
|
}
|
|
876
|
-
_handleOutboundPacketStream() {
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
_d = false;
|
|
824
|
+
async _handleOutboundPacketStream() {
|
|
825
|
+
for await (let packet of this.outboundPacketStream) {
|
|
826
|
+
if ('resolve' in packet) {
|
|
827
|
+
// Invoke has no middleware, so there is no need to await here.
|
|
828
|
+
(async () => {
|
|
829
|
+
let result;
|
|
883
830
|
try {
|
|
884
|
-
|
|
885
|
-
if ('resolve' in packet) {
|
|
886
|
-
// Invoke has no middleware, so there is no need to await here.
|
|
887
|
-
(() => __awaiter(this, void 0, void 0, function* () {
|
|
888
|
-
let result;
|
|
889
|
-
try {
|
|
890
|
-
result = yield this._invoke(packet);
|
|
891
|
-
}
|
|
892
|
-
catch (error) {
|
|
893
|
-
packet.reject(error);
|
|
894
|
-
return;
|
|
895
|
-
}
|
|
896
|
-
packet.resolve(result);
|
|
897
|
-
}))();
|
|
898
|
-
this.outboundSentMessageCount++;
|
|
899
|
-
continue;
|
|
900
|
-
}
|
|
901
|
-
yield this._processTransmit(packet);
|
|
902
|
-
this.outboundSentMessageCount++;
|
|
831
|
+
result = await this._invoke(packet);
|
|
903
832
|
}
|
|
904
|
-
|
|
905
|
-
|
|
833
|
+
catch (error) {
|
|
834
|
+
packet.reject(error);
|
|
835
|
+
return;
|
|
906
836
|
}
|
|
907
|
-
|
|
837
|
+
packet.resolve(result);
|
|
838
|
+
})();
|
|
839
|
+
this.outboundSentMessageCount++;
|
|
840
|
+
continue;
|
|
908
841
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
|
|
913
|
-
}
|
|
914
|
-
finally { if (e_2) throw e_2.error; }
|
|
915
|
-
}
|
|
916
|
-
});
|
|
842
|
+
await this._processTransmit(packet);
|
|
843
|
+
this.outboundSentMessageCount++;
|
|
844
|
+
}
|
|
917
845
|
}
|
|
918
846
|
_transmit(event, data, options) {
|
|
919
847
|
if (this.cloneData) {
|
|
@@ -928,31 +856,29 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
928
856
|
}
|
|
929
857
|
transmit(event, data, options) {
|
|
930
858
|
if (this.state !== SocketState.OPEN) {
|
|
931
|
-
let error = new BadConnectionError(`Socket transmit
|
|
859
|
+
let error = new BadConnectionError(`Socket transmit ${event} event was aborted due to a bad connection`, 'connectAbort');
|
|
932
860
|
this.emitError(error);
|
|
933
861
|
return;
|
|
934
862
|
}
|
|
935
863
|
this._transmit(event, data, options);
|
|
936
864
|
}
|
|
937
|
-
invoke(event, data, options) {
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
reject
|
|
955
|
-
});
|
|
865
|
+
async invoke(event, data, options) {
|
|
866
|
+
if (this.state !== SocketState.OPEN) {
|
|
867
|
+
const error = new BadConnectionError(`Socket invoke ${event} event was aborted due to a bad connection`, 'connectAbort');
|
|
868
|
+
this.emitError(error);
|
|
869
|
+
throw error;
|
|
870
|
+
}
|
|
871
|
+
if (this.cloneData) {
|
|
872
|
+
data = cloneDeep(data);
|
|
873
|
+
}
|
|
874
|
+
this.outboundPreparedMessageCount++;
|
|
875
|
+
return new Promise((resolve, reject) => {
|
|
876
|
+
this.outboundPacketStream.write({
|
|
877
|
+
event,
|
|
878
|
+
data,
|
|
879
|
+
options,
|
|
880
|
+
resolve,
|
|
881
|
+
reject
|
|
956
882
|
});
|
|
957
883
|
});
|
|
958
884
|
}
|
|
@@ -962,86 +888,82 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
962
888
|
listen(eventName) {
|
|
963
889
|
return super.listen(eventName);
|
|
964
890
|
}
|
|
965
|
-
_processTransmit(packet) {
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
891
|
+
async _processTransmit(packet) {
|
|
892
|
+
let newData;
|
|
893
|
+
let useCache = packet.options ? packet.options.useCache : false;
|
|
894
|
+
if (isPublishOutPacket(packet)) {
|
|
895
|
+
const action = new ActionPublishOut(this);
|
|
896
|
+
if (packet.data !== undefined) {
|
|
897
|
+
action.channel = packet.data.channel;
|
|
898
|
+
action.data = packet.data.data;
|
|
899
|
+
}
|
|
900
|
+
useCache = !this.server.hasMiddleware(this.middlewareOutboundStream.type);
|
|
901
|
+
try {
|
|
902
|
+
const { data, options } = await this.server._processMiddlewareAction(this.middlewareOutboundStream, action, this);
|
|
903
|
+
newData = data;
|
|
904
|
+
useCache = options == null ? useCache : options.useCache;
|
|
905
|
+
}
|
|
906
|
+
catch (error) {
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
else {
|
|
911
|
+
newData = packet.data;
|
|
912
|
+
}
|
|
913
|
+
if (packet.options && useCache && packet.options.stringifiedData != null && !this.isBufferingBatch) {
|
|
914
|
+
// Optimized
|
|
915
|
+
this.send(packet.options.stringifiedData);
|
|
916
|
+
}
|
|
917
|
+
else {
|
|
918
|
+
const eventObject = {
|
|
919
|
+
event: packet.event
|
|
920
|
+
};
|
|
969
921
|
if (isPublishOutPacket(packet)) {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
action.channel = packet.data.channel;
|
|
973
|
-
action.data = packet.data.data;
|
|
974
|
-
}
|
|
975
|
-
useCache = !this.server.hasMiddleware(this.middlewareOutboundStream.type);
|
|
976
|
-
try {
|
|
977
|
-
const { data, options } = yield this.server._processMiddlewareAction(this.middlewareOutboundStream, action, this);
|
|
978
|
-
newData = data;
|
|
979
|
-
useCache = options == null ? useCache : options.useCache;
|
|
980
|
-
}
|
|
981
|
-
catch (error) {
|
|
982
|
-
return;
|
|
983
|
-
}
|
|
922
|
+
eventObject.data = packet.data || {};
|
|
923
|
+
eventObject.data.data = newData;
|
|
984
924
|
}
|
|
985
925
|
else {
|
|
986
|
-
|
|
926
|
+
eventObject.data = newData;
|
|
987
927
|
}
|
|
988
|
-
|
|
928
|
+
this.sendObject(eventObject);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
async _invoke({ event, data, options }) {
|
|
932
|
+
options = options || {};
|
|
933
|
+
return new Promise((resolve, reject) => {
|
|
934
|
+
const eventObject = {
|
|
935
|
+
event,
|
|
936
|
+
cid: this._nextCallId()
|
|
937
|
+
};
|
|
938
|
+
if (data !== undefined) {
|
|
939
|
+
eventObject.data = data;
|
|
940
|
+
}
|
|
941
|
+
const ackTimeout = options.ackTimeout == null ? this.server.ackTimeout : options.ackTimeout;
|
|
942
|
+
const timeout = setTimeout(() => {
|
|
943
|
+
let error = new TimeoutError(`Event response for ${event} event timed out`);
|
|
944
|
+
delete this._callbackMap[eventObject.cid];
|
|
945
|
+
reject(error);
|
|
946
|
+
}, ackTimeout);
|
|
947
|
+
this._callbackMap[eventObject.cid] = {
|
|
948
|
+
event,
|
|
949
|
+
callback: (err, result) => {
|
|
950
|
+
if (err) {
|
|
951
|
+
reject(err);
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
resolve(result);
|
|
955
|
+
},
|
|
956
|
+
timeout
|
|
957
|
+
};
|
|
958
|
+
if (options.useCache && options.stringifiedData != null && !this.isBufferingBatch) {
|
|
989
959
|
// Optimized
|
|
990
|
-
this.send(
|
|
960
|
+
this.send(options.stringifiedData);
|
|
991
961
|
}
|
|
992
962
|
else {
|
|
993
|
-
const eventObject = {
|
|
994
|
-
event: packet.event
|
|
995
|
-
};
|
|
996
|
-
if (isPublishOutPacket(packet)) {
|
|
997
|
-
eventObject.data = packet.data || {};
|
|
998
|
-
eventObject.data.data = newData;
|
|
999
|
-
}
|
|
1000
|
-
else {
|
|
1001
|
-
eventObject.data = newData;
|
|
1002
|
-
}
|
|
1003
963
|
this.sendObject(eventObject);
|
|
1004
964
|
}
|
|
1005
965
|
});
|
|
1006
966
|
}
|
|
1007
|
-
_invoke({ event, data, options }) {
|
|
1008
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1009
|
-
options = options || {};
|
|
1010
|
-
return new Promise((resolve, reject) => {
|
|
1011
|
-
const eventObject = {
|
|
1012
|
-
event,
|
|
1013
|
-
cid: this._nextCallId()
|
|
1014
|
-
};
|
|
1015
|
-
if (data !== undefined) {
|
|
1016
|
-
eventObject.data = data;
|
|
1017
|
-
}
|
|
1018
|
-
const ackTimeout = options.ackTimeout == null ? this.server.ackTimeout : options.ackTimeout;
|
|
1019
|
-
const timeout = setTimeout(() => {
|
|
1020
|
-
let error = new TimeoutError(`Event response for "${event}" timed out`);
|
|
1021
|
-
delete this._callbackMap[eventObject.cid];
|
|
1022
|
-
reject(error);
|
|
1023
|
-
}, ackTimeout);
|
|
1024
|
-
this._callbackMap[eventObject.cid] = {
|
|
1025
|
-
event,
|
|
1026
|
-
callback: (err, result) => {
|
|
1027
|
-
if (err) {
|
|
1028
|
-
reject(err);
|
|
1029
|
-
return;
|
|
1030
|
-
}
|
|
1031
|
-
resolve(result);
|
|
1032
|
-
},
|
|
1033
|
-
timeout
|
|
1034
|
-
};
|
|
1035
|
-
if (options.useCache && options.stringifiedData != null && !this.isBufferingBatch) {
|
|
1036
|
-
// Optimized
|
|
1037
|
-
this.send(options.stringifiedData);
|
|
1038
|
-
}
|
|
1039
|
-
else {
|
|
1040
|
-
this.sendObject(eventObject);
|
|
1041
|
-
}
|
|
1042
|
-
});
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
967
|
triggerAuthenticationEvents(oldAuthState) {
|
|
1046
968
|
if (oldAuthState !== AuthState.AUTHENTICATED) {
|
|
1047
969
|
let stateChangeData = {
|
|
@@ -1050,7 +972,10 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1050
972
|
authToken: this.authToken
|
|
1051
973
|
};
|
|
1052
974
|
this.emit('authStateChange', stateChangeData);
|
|
1053
|
-
this.server.emit('authenticationStateChange',
|
|
975
|
+
this.server.emit('authenticationStateChange', {
|
|
976
|
+
socket: this,
|
|
977
|
+
...stateChangeData
|
|
978
|
+
});
|
|
1054
979
|
}
|
|
1055
980
|
this.emit('authenticate', { authToken: this.authToken });
|
|
1056
981
|
this.server.emit('authentication', {
|
|
@@ -1058,87 +983,91 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1058
983
|
authToken: this.authToken
|
|
1059
984
|
});
|
|
1060
985
|
}
|
|
1061
|
-
setAuthToken(data, options) {
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
986
|
+
async setAuthToken(data, options) {
|
|
987
|
+
if (this.state === SocketState.CONNECTING) {
|
|
988
|
+
const err = new InvalidActionError('Cannot call setAuthToken before completing the handshake');
|
|
989
|
+
this.emitError(err);
|
|
990
|
+
throw err;
|
|
991
|
+
}
|
|
992
|
+
const authToken = cloneDeep(data);
|
|
993
|
+
const oldAuthState = this.authState;
|
|
994
|
+
this.authState = AuthState.AUTHENTICATED;
|
|
995
|
+
if (options == null) {
|
|
996
|
+
options = {};
|
|
997
|
+
}
|
|
998
|
+
else {
|
|
999
|
+
options = { ...options };
|
|
1000
|
+
if (options.algorithm != null) {
|
|
1001
|
+
delete options.algorithm;
|
|
1002
|
+
let err = new InvalidArgumentsError('Cannot change auth token algorithm at runtime - It must be specified as a config option on launch');
|
|
1065
1003
|
this.emitError(err);
|
|
1066
|
-
throw err;
|
|
1067
1004
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1005
|
+
}
|
|
1006
|
+
options.mutatePayload = true;
|
|
1007
|
+
const rejectOnFailedDelivery = options.rejectOnFailedDelivery;
|
|
1008
|
+
delete options.rejectOnFailedDelivery;
|
|
1009
|
+
const defaultSignatureOptions = this.server.defaultSignatureOptions;
|
|
1010
|
+
// We cannot have the exp claim on the token and the expiresIn option
|
|
1011
|
+
// set at the same time or else auth.signToken will throw an error.
|
|
1012
|
+
let expiresIn;
|
|
1013
|
+
if (options.expiresIn == null) {
|
|
1014
|
+
expiresIn = defaultSignatureOptions.expiresIn;
|
|
1015
|
+
}
|
|
1016
|
+
else {
|
|
1017
|
+
expiresIn = options.expiresIn;
|
|
1018
|
+
}
|
|
1019
|
+
if (authToken) {
|
|
1020
|
+
if (authToken.exp == null) {
|
|
1021
|
+
options.expiresIn = expiresIn;
|
|
1073
1022
|
}
|
|
1074
1023
|
else {
|
|
1075
|
-
options
|
|
1076
|
-
if (options.algorithm != null) {
|
|
1077
|
-
delete options.algorithm;
|
|
1078
|
-
let err = new InvalidArgumentsError('Cannot change auth token algorithm at runtime - It must be specified as a config option on launch');
|
|
1079
|
-
this.emitError(err);
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
options.mutatePayload = true;
|
|
1083
|
-
const rejectOnFailedDelivery = options.rejectOnFailedDelivery;
|
|
1084
|
-
delete options.rejectOnFailedDelivery;
|
|
1085
|
-
const defaultSignatureOptions = this.server.defaultSignatureOptions;
|
|
1086
|
-
// We cannot have the exp claim on the token and the expiresIn option
|
|
1087
|
-
// set at the same time or else auth.signToken will throw an error.
|
|
1088
|
-
let expiresIn;
|
|
1089
|
-
if (options.expiresIn == null) {
|
|
1090
|
-
expiresIn = defaultSignatureOptions.expiresIn;
|
|
1024
|
+
delete options.expiresIn;
|
|
1091
1025
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1026
|
+
}
|
|
1027
|
+
else {
|
|
1028
|
+
options.expiresIn = expiresIn;
|
|
1029
|
+
}
|
|
1030
|
+
// Always use the default algorithm since it cannot be changed at runtime.
|
|
1031
|
+
if (defaultSignatureOptions.algorithm != null) {
|
|
1032
|
+
options.algorithm = defaultSignatureOptions.algorithm;
|
|
1033
|
+
}
|
|
1034
|
+
this.authToken = authToken;
|
|
1035
|
+
let signedAuthToken;
|
|
1036
|
+
try {
|
|
1037
|
+
signedAuthToken = await this.server.auth.signToken(authToken, this.server.signatureKey, options);
|
|
1038
|
+
}
|
|
1039
|
+
catch (error) {
|
|
1040
|
+
this.emitError(error);
|
|
1041
|
+
this._destroy(4002, error.toString());
|
|
1042
|
+
this.socket.close(4002);
|
|
1043
|
+
throw error;
|
|
1044
|
+
}
|
|
1045
|
+
if (this.authToken === authToken) {
|
|
1046
|
+
this.signedAuthToken = signedAuthToken;
|
|
1047
|
+
this.emit('authTokenSigned', { signedAuthToken });
|
|
1048
|
+
}
|
|
1049
|
+
this.triggerAuthenticationEvents(oldAuthState);
|
|
1050
|
+
const tokenData = {
|
|
1051
|
+
token: signedAuthToken
|
|
1052
|
+
};
|
|
1053
|
+
if (rejectOnFailedDelivery) {
|
|
1054
|
+
try {
|
|
1055
|
+
await this.invoke('#setAuthToken', tokenData);
|
|
1094
1056
|
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1057
|
+
catch (err) {
|
|
1058
|
+
let error;
|
|
1059
|
+
if (err && typeof err.message === 'string') {
|
|
1060
|
+
error = new AuthError(`Failed to deliver auth token to client - ${err.message}`);
|
|
1098
1061
|
}
|
|
1099
1062
|
else {
|
|
1100
|
-
|
|
1063
|
+
error = new AuthError('Failed to confirm delivery of auth token to client due to malformatted error response');
|
|
1101
1064
|
}
|
|
1102
|
-
}
|
|
1103
|
-
else {
|
|
1104
|
-
options.expiresIn = expiresIn;
|
|
1105
|
-
}
|
|
1106
|
-
// Always use the default algorithm since it cannot be changed at runtime.
|
|
1107
|
-
if (defaultSignatureOptions.algorithm != null) {
|
|
1108
|
-
options.algorithm = defaultSignatureOptions.algorithm;
|
|
1109
|
-
}
|
|
1110
|
-
this.authToken = authToken;
|
|
1111
|
-
let signedAuthToken;
|
|
1112
|
-
try {
|
|
1113
|
-
signedAuthToken = yield this.server.auth.signToken(authToken, this.server.signatureKey, options);
|
|
1114
|
-
}
|
|
1115
|
-
catch (error) {
|
|
1116
1065
|
this.emitError(error);
|
|
1117
|
-
this._destroy(4002, error.toString());
|
|
1118
|
-
this.socket.close(4002);
|
|
1119
1066
|
throw error;
|
|
1120
1067
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
}
|
|
1125
|
-
this.triggerAuthenticationEvents(oldAuthState);
|
|
1126
|
-
const tokenData = {
|
|
1127
|
-
token: signedAuthToken
|
|
1128
|
-
};
|
|
1129
|
-
if (rejectOnFailedDelivery) {
|
|
1130
|
-
try {
|
|
1131
|
-
yield this.invoke('#setAuthToken', tokenData);
|
|
1132
|
-
}
|
|
1133
|
-
catch (err) {
|
|
1134
|
-
const error = new AuthError(`Failed to deliver auth token to client - ${err}`);
|
|
1135
|
-
this.emitError(error);
|
|
1136
|
-
throw error;
|
|
1137
|
-
}
|
|
1138
|
-
return;
|
|
1139
|
-
}
|
|
1140
|
-
this.transmit('#setAuthToken', tokenData);
|
|
1141
|
-
});
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
this.transmit('#setAuthToken', tokenData);
|
|
1142
1071
|
}
|
|
1143
1072
|
getAuthToken() {
|
|
1144
1073
|
return this.authToken;
|
|
@@ -1155,7 +1084,10 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1155
1084
|
newAuthState: this.authState
|
|
1156
1085
|
};
|
|
1157
1086
|
this.emit('authStateChange', stateChangeData);
|
|
1158
|
-
this.server.emit('authenticationStateChange',
|
|
1087
|
+
this.server.emit('authenticationStateChange', {
|
|
1088
|
+
socket: this,
|
|
1089
|
+
...stateChangeData
|
|
1090
|
+
});
|
|
1159
1091
|
}
|
|
1160
1092
|
this.emit('deauthenticate', { oldAuthToken });
|
|
1161
1093
|
this.server.emit('deauthentication', {
|
|
@@ -1163,23 +1095,21 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1163
1095
|
oldAuthToken
|
|
1164
1096
|
});
|
|
1165
1097
|
}
|
|
1166
|
-
deauthenticate(options) {
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
throw error;
|
|
1177
|
-
}
|
|
1098
|
+
async deauthenticate(options) {
|
|
1099
|
+
this.deauthenticateSelf();
|
|
1100
|
+
if (options && options.rejectOnFailedDelivery) {
|
|
1101
|
+
try {
|
|
1102
|
+
await this.invoke('#removeAuthToken');
|
|
1103
|
+
}
|
|
1104
|
+
catch (error) {
|
|
1105
|
+
this.emitError(error);
|
|
1106
|
+
if (options && options.rejectOnFailedDelivery) {
|
|
1107
|
+
throw error;
|
|
1178
1108
|
}
|
|
1179
|
-
return;
|
|
1180
1109
|
}
|
|
1181
|
-
|
|
1182
|
-
}
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
this._transmit('#removeAuthToken');
|
|
1183
1113
|
}
|
|
1184
1114
|
kickOut(channel, message) {
|
|
1185
1115
|
const channels = channel ? [channel] : Object.keys(this.channelSubscriptions);
|
|
@@ -1203,7 +1133,7 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1203
1133
|
return null;
|
|
1204
1134
|
}
|
|
1205
1135
|
isAuthTokenExpired(token) {
|
|
1206
|
-
if (
|
|
1136
|
+
if (token?.exp != null) {
|
|
1207
1137
|
const currentTime = Date.now();
|
|
1208
1138
|
const expiryMilliseconds = token.exp * 1000;
|
|
1209
1139
|
return currentTime > expiryMilliseconds;
|
|
@@ -1234,61 +1164,57 @@ export class ServerSocket extends AsyncStreamEmitter {
|
|
|
1234
1164
|
signedAuthToken
|
|
1235
1165
|
});
|
|
1236
1166
|
}
|
|
1237
|
-
_validateAuthToken(signedAuthToken) {
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
const authTokenError = this._processTokenError(error);
|
|
1246
|
-
return {
|
|
1247
|
-
signedAuthToken,
|
|
1248
|
-
authTokenError,
|
|
1249
|
-
authToken: null,
|
|
1250
|
-
authState: AuthState.UNAUTHENTICATED
|
|
1251
|
-
};
|
|
1252
|
-
}
|
|
1167
|
+
async _validateAuthToken(signedAuthToken) {
|
|
1168
|
+
const verificationOptions = Object.assign({ socket: this }, this.server.defaultVerificationOptions);
|
|
1169
|
+
let authToken;
|
|
1170
|
+
try {
|
|
1171
|
+
authToken = await this.server.auth.verifyToken(signedAuthToken, this.server.verificationKey, verificationOptions);
|
|
1172
|
+
}
|
|
1173
|
+
catch (error) {
|
|
1174
|
+
const authTokenError = this._processTokenError(error);
|
|
1253
1175
|
return {
|
|
1254
1176
|
signedAuthToken,
|
|
1255
|
-
authTokenError
|
|
1256
|
-
authToken,
|
|
1257
|
-
authState: AuthState.
|
|
1177
|
+
authTokenError,
|
|
1178
|
+
authToken: null,
|
|
1179
|
+
authState: AuthState.UNAUTHENTICATED
|
|
1258
1180
|
};
|
|
1259
|
-
}
|
|
1181
|
+
}
|
|
1182
|
+
return {
|
|
1183
|
+
signedAuthToken,
|
|
1184
|
+
authTokenError: null,
|
|
1185
|
+
authToken,
|
|
1186
|
+
authState: AuthState.AUTHENTICATED
|
|
1187
|
+
};
|
|
1260
1188
|
}
|
|
1261
|
-
_processAuthentication({ signedAuthToken, authTokenError, authToken }) {
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
this._emitBadAuthTokenError(authTokenError, signedAuthToken);
|
|
1273
|
-
}
|
|
1189
|
+
async _processAuthentication({ signedAuthToken, authTokenError, authToken }) {
|
|
1190
|
+
if (authTokenError) {
|
|
1191
|
+
this.signedAuthToken = null;
|
|
1192
|
+
this.authToken = null;
|
|
1193
|
+
this.authState = AuthState.UNAUTHENTICATED;
|
|
1194
|
+
// If the error is related to the JWT being badly formatted, then we will
|
|
1195
|
+
// treat the error as a socket error.
|
|
1196
|
+
if (signedAuthToken != null) {
|
|
1197
|
+
this.emitError(authTokenError);
|
|
1198
|
+
if (authTokenError instanceof AuthTokenError) {
|
|
1199
|
+
this._emitBadAuthTokenError(authTokenError, signedAuthToken);
|
|
1274
1200
|
}
|
|
1275
|
-
throw authTokenError;
|
|
1276
|
-
}
|
|
1277
|
-
this.signedAuthToken = signedAuthToken;
|
|
1278
|
-
this.authToken = authToken;
|
|
1279
|
-
this.authState = AuthState.AUTHENTICATED;
|
|
1280
|
-
const action = new ActionAuthenticate(this, authToken, signedAuthToken);
|
|
1281
|
-
try {
|
|
1282
|
-
yield this.server._processMiddlewareAction(this.middlewareInboundStream, action, this);
|
|
1283
1201
|
}
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1202
|
+
throw authTokenError;
|
|
1203
|
+
}
|
|
1204
|
+
this.signedAuthToken = signedAuthToken;
|
|
1205
|
+
this.authToken = authToken;
|
|
1206
|
+
this.authState = AuthState.AUTHENTICATED;
|
|
1207
|
+
const action = new ActionAuthenticate(this, authToken, signedAuthToken);
|
|
1208
|
+
try {
|
|
1209
|
+
await this.server._processMiddlewareAction(this.middlewareInboundStream, action, this);
|
|
1210
|
+
}
|
|
1211
|
+
catch (error) {
|
|
1212
|
+
this.authToken = null;
|
|
1213
|
+
this.authState = AuthState.UNAUTHENTICATED;
|
|
1214
|
+
if (error instanceof AuthTokenError) {
|
|
1215
|
+
this._emitBadAuthTokenError(error, signedAuthToken);
|
|
1291
1216
|
}
|
|
1292
|
-
|
|
1217
|
+
throw error;
|
|
1218
|
+
}
|
|
1293
1219
|
}
|
|
1294
1220
|
}
|