@monterosa/sdk-enmasse-kit 2.0.0-rc.2 → 2.0.0-rc.3
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.cjs +2180 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +8 -7
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2180 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var sdkUtil = require('@monterosa/sdk-util');
|
|
4
|
+
var sdkStorageKit = require('@monterosa/sdk-storage-kit');
|
|
5
|
+
var sdkLauncherKit = require('@monterosa/sdk-launcher-kit');
|
|
6
|
+
|
|
7
|
+
const ARG_OVERRIDE_METHODS = 'enmasse_override_methods';
|
|
8
|
+
const ARG_DEBUG = 'enmasse_debug';
|
|
9
|
+
const ARG_CONFIG = 'enmasse_config';
|
|
10
|
+
|
|
11
|
+
const SSCP_KLASS_AUTH = 'auth';
|
|
12
|
+
const SSCP_KLASS_AUTHR = 'authr';
|
|
13
|
+
const SSCP_KLASS_AUTHOK = 'authok';
|
|
14
|
+
const SSCP_KLASS_PING = 'ping';
|
|
15
|
+
const SSCP_KLASS_SUB = 'sub';
|
|
16
|
+
const SSCP_KLASS_UNSUB = 'unsub';
|
|
17
|
+
const SSCP_KLASS_EOC = 'eoc';
|
|
18
|
+
const SSCP_KLASS_LOGIN = 'login';
|
|
19
|
+
const SSCP_KLASS_LOGIN_OK = 'login_ok';
|
|
20
|
+
const SSCP_KLASS_LOGIN_FAIL = 'login_fail';
|
|
21
|
+
const SSCP_KLASS_LOGOUT = 'logout';
|
|
22
|
+
const SSCP_KLASS_COUNTER = 'counter';
|
|
23
|
+
|
|
24
|
+
const getSettingFor = (name) => {
|
|
25
|
+
if (sdkUtil.checkAvailability()) {
|
|
26
|
+
const value = sdkUtil.getItem(name);
|
|
27
|
+
|
|
28
|
+
if (value !== null) {
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Guarding the use of the window object in environments where it might not be
|
|
34
|
+
// available, such as during server - side rendering in a framework like Next.js
|
|
35
|
+
if (typeof window === 'undefined') {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const { searchParams } = new URL(window.location.href);
|
|
40
|
+
|
|
41
|
+
if (searchParams.has(name)) {
|
|
42
|
+
return searchParams.get(name);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return false;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const getSettingForMethods = () => {
|
|
49
|
+
const value = getSettingFor(ARG_OVERRIDE_METHODS);
|
|
50
|
+
|
|
51
|
+
if (typeof value === 'string') {
|
|
52
|
+
return value.split(',');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return undefined;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const ENMASSE_OVERRIDE_METHODS = getSettingForMethods();
|
|
59
|
+
const ENMASSE_DEBUG = getSettingFor(ARG_DEBUG);
|
|
60
|
+
const ENMASSE_CONFIG = getSettingFor(ARG_CONFIG);
|
|
61
|
+
|
|
62
|
+
var version = "2.0.0-rc.3";
|
|
63
|
+
|
|
64
|
+
/* eslint no-bitwise: "off" */
|
|
65
|
+
|
|
66
|
+
const TYPE_PROTOCOL = 1; // 0000 0000 0001
|
|
67
|
+
const TYPE_MANAGER = 2; // 0000 0000 0010
|
|
68
|
+
const TYPE_TRANSPORT = 4; // 0000 0000 0100
|
|
69
|
+
const TYPE_DRIVER = 8; // 0000 0000 1000
|
|
70
|
+
const TYPE_QUEUE = 16; // 0000 0001 0000
|
|
71
|
+
const TYPE_TIME = 32; // 0000 0010 0000
|
|
72
|
+
const TYPE_MANAGER_EXTRA = 64; // 0000 0100 0000
|
|
73
|
+
const TYPE_DRIVER_EXTRA = 128; // 0000 1000 0000
|
|
74
|
+
const TYPE_SERVICE = 256; // 0001 0000 0000
|
|
75
|
+
|
|
76
|
+
const LEVELS = {
|
|
77
|
+
brief: TYPE_PROTOCOL,
|
|
78
|
+
full: TYPE_PROTOCOL | TYPE_MANAGER | TYPE_TRANSPORT | TYPE_DRIVER,
|
|
79
|
+
exhaustive:
|
|
80
|
+
TYPE_PROTOCOL |
|
|
81
|
+
TYPE_MANAGER |
|
|
82
|
+
TYPE_MANAGER_EXTRA |
|
|
83
|
+
TYPE_TRANSPORT |
|
|
84
|
+
TYPE_DRIVER |
|
|
85
|
+
TYPE_DRIVER_EXTRA |
|
|
86
|
+
TYPE_QUEUE |
|
|
87
|
+
TYPE_TIME |
|
|
88
|
+
TYPE_SERVICE,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// eslint-disable-next-line
|
|
92
|
+
let log = () => {};
|
|
93
|
+
|
|
94
|
+
if (ENMASSE_DEBUG) {
|
|
95
|
+
log = (...args) => {
|
|
96
|
+
if (typeof console === 'undefined' || !console.log) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// parse arguments
|
|
101
|
+
// var args = Array.prototype.slice.call(arguments);
|
|
102
|
+
|
|
103
|
+
// the first argument is the debug type
|
|
104
|
+
const [type] = args;
|
|
105
|
+
|
|
106
|
+
// the rest of arguments are arbitrary data
|
|
107
|
+
const rest = args.slice(1);
|
|
108
|
+
|
|
109
|
+
// const time = ['getMinutes', 'getSeconds']
|
|
110
|
+
// .map((f) => new Date()[f]())
|
|
111
|
+
// .map((v) => (v < 10 ? '0' : '') + v)
|
|
112
|
+
// .join(':');
|
|
113
|
+
|
|
114
|
+
// add current time
|
|
115
|
+
// rest.unshift(time);
|
|
116
|
+
|
|
117
|
+
// do not log if mask doesn't contain current type
|
|
118
|
+
if ((LEVELS[ENMASSE_DEBUG] & type) === 0) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(...rest);
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class Queue {
|
|
127
|
+
constructor(config = {}) {
|
|
128
|
+
// the main storage for messages
|
|
129
|
+
this.queue = [];
|
|
130
|
+
|
|
131
|
+
// stash of the queue
|
|
132
|
+
this.stashed = [];
|
|
133
|
+
|
|
134
|
+
this.running = false;
|
|
135
|
+
|
|
136
|
+
this.runner = typeof config.runner === 'function' ? config.runner : null;
|
|
137
|
+
|
|
138
|
+
// list of channels we subscribed to
|
|
139
|
+
this.subscriptions = [];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
push(message, force = false) {
|
|
143
|
+
log(TYPE_QUEUE, 'Queue::push', message, force);
|
|
144
|
+
|
|
145
|
+
const { klass, channel } = message;
|
|
146
|
+
|
|
147
|
+
if (!force) {
|
|
148
|
+
switch (klass) {
|
|
149
|
+
case SSCP_KLASS_LOGIN:
|
|
150
|
+
case SSCP_KLASS_LOGOUT:
|
|
151
|
+
case SSCP_KLASS_AUTHR:
|
|
152
|
+
break;
|
|
153
|
+
case SSCP_KLASS_SUB:
|
|
154
|
+
if (this.subscriptions.indexOf(channel) === -1) {
|
|
155
|
+
this.subscriptions.push(channel);
|
|
156
|
+
} else {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
case SSCP_KLASS_UNSUB: {
|
|
161
|
+
const index = this.subscriptions.indexOf(channel);
|
|
162
|
+
|
|
163
|
+
if (index !== -1) {
|
|
164
|
+
this.subscriptions.splice(index, 1);
|
|
165
|
+
} else {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
default:
|
|
171
|
+
if (this.subscriptions.indexOf(channel) === -1) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.queue.push(message);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
getSubscriptions() {
|
|
182
|
+
return this.subscriptions;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
run() {
|
|
186
|
+
log(
|
|
187
|
+
TYPE_QUEUE,
|
|
188
|
+
'Queue::run',
|
|
189
|
+
`running=${this.running}, head=${this.queue[0]}`,
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
// abort if whether
|
|
193
|
+
// 1. runner function is not set
|
|
194
|
+
// 2. OR queue is already running
|
|
195
|
+
// 3. OR there is no messages in the queue
|
|
196
|
+
if (this.runner === null || this.running || !this.queue[0]) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
this.running = true;
|
|
201
|
+
|
|
202
|
+
this.runner(this.queue.shift());
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
success() {
|
|
206
|
+
log(TYPE_QUEUE, 'Queue::success');
|
|
207
|
+
|
|
208
|
+
this.running = false;
|
|
209
|
+
|
|
210
|
+
this.run();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
failure() {
|
|
214
|
+
log(TYPE_QUEUE, 'Queue::failure');
|
|
215
|
+
|
|
216
|
+
this.running = false;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
stash() {
|
|
220
|
+
log(TYPE_QUEUE, 'Queue::stash');
|
|
221
|
+
|
|
222
|
+
let item;
|
|
223
|
+
|
|
224
|
+
// eslint-disable-next-line
|
|
225
|
+
while (undefined !== (item = this.queue.shift())) {
|
|
226
|
+
this.stashed.push(item);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
unstash() {
|
|
231
|
+
log(TYPE_QUEUE, 'Queue::unstash');
|
|
232
|
+
|
|
233
|
+
let item;
|
|
234
|
+
|
|
235
|
+
// eslint-disable-next-line
|
|
236
|
+
while (undefined !== (item = this.stashed.shift())) {
|
|
237
|
+
this.queue.push(item);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Returns current local timestamp
|
|
243
|
+
const local = () => new Date() / 1000;
|
|
244
|
+
|
|
245
|
+
// Server time default to local time
|
|
246
|
+
let serverTime = local();
|
|
247
|
+
|
|
248
|
+
// Time when the server time was received on the client
|
|
249
|
+
let clientTimeAtSync = local();
|
|
250
|
+
|
|
251
|
+
const setTime = (newTime) => {
|
|
252
|
+
log(TYPE_TIME, 'Time::setTime', newTime);
|
|
253
|
+
|
|
254
|
+
serverTime = newTime;
|
|
255
|
+
// offset = local() - time;
|
|
256
|
+
clientTimeAtSync = local();
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const now = () => {
|
|
260
|
+
const elapsedTime = local() - clientTimeAtSync;
|
|
261
|
+
|
|
262
|
+
return Math.round(serverTime + elapsedTime);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
class Transport extends sdkUtil.Emitter {
|
|
266
|
+
// generic events
|
|
267
|
+
static ON_READY = 'ready';
|
|
268
|
+
static ON_MESSAGE = 'message';
|
|
269
|
+
|
|
270
|
+
// connection state events
|
|
271
|
+
static ON_CONNECTED = 'connected';
|
|
272
|
+
static ON_CONNECT_FAILED = 'connect_failed';
|
|
273
|
+
static ON_CONNECT_LOST = 'connect_lost';
|
|
274
|
+
static ON_DISCONNECTED = 'disconnected';
|
|
275
|
+
|
|
276
|
+
// states
|
|
277
|
+
static STATE_CONNECTED = 'connected';
|
|
278
|
+
static STATE_CONNECTING = 'connecting';
|
|
279
|
+
static STATE_DISCONNECTED = 'disconnected';
|
|
280
|
+
static STATE_DISCONNECTING = 'disconnecting';
|
|
281
|
+
|
|
282
|
+
constructor() {
|
|
283
|
+
super();
|
|
284
|
+
|
|
285
|
+
this.state = this.STATE_DISCONNECTED;
|
|
286
|
+
|
|
287
|
+
this.trigger = this.emit;
|
|
288
|
+
this.bind = this.on;
|
|
289
|
+
this.unbind = this.off;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/* eslint class-methods-use-this: "off" */
|
|
294
|
+
|
|
295
|
+
class Driver extends sdkUtil.Emitter {
|
|
296
|
+
static ON_READY = 'ready';
|
|
297
|
+
static ON_MESSAGE = 'message';
|
|
298
|
+
static ON_CONNECTED = 'connected';
|
|
299
|
+
static ON_DISCONNECTED = 'disconnected';
|
|
300
|
+
|
|
301
|
+
constructor() {
|
|
302
|
+
super();
|
|
303
|
+
|
|
304
|
+
this.connected = false;
|
|
305
|
+
|
|
306
|
+
this.trigger = this.emit;
|
|
307
|
+
this.bind = this.on;
|
|
308
|
+
this.unbind = this.off;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
connect() {}
|
|
312
|
+
|
|
313
|
+
disconnect() {}
|
|
314
|
+
|
|
315
|
+
// Arguments:
|
|
316
|
+
//
|
|
317
|
+
// data = null
|
|
318
|
+
// success = () => {}
|
|
319
|
+
// failure = () => {}
|
|
320
|
+
send() {}
|
|
321
|
+
|
|
322
|
+
init() {
|
|
323
|
+
this.trigger(Driver.ON_READY);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const globals$1 = sdkUtil.getGlobal();
|
|
328
|
+
|
|
329
|
+
class XHRDriver extends Driver {
|
|
330
|
+
constructor(config = {}) {
|
|
331
|
+
super();
|
|
332
|
+
|
|
333
|
+
this.config = config;
|
|
334
|
+
this.requests = {};
|
|
335
|
+
this.requestIdx = 0;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// CORS request wrapper
|
|
339
|
+
_request(url, success = () => {}, failure = () => {}, abort = () => {}) {
|
|
340
|
+
this.requestIdx += 1;
|
|
341
|
+
|
|
342
|
+
log(
|
|
343
|
+
TYPE_DRIVER_EXTRA,
|
|
344
|
+
`XHRDriver::request url=${url}, idx=${this.requestIdx}`,
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
const self = this;
|
|
348
|
+
let xhr = new XMLHttpRequest();
|
|
349
|
+
const method = 'POST';
|
|
350
|
+
|
|
351
|
+
if (typeof XDomainRequest !== 'undefined') {
|
|
352
|
+
xhr = new XDomainRequest();
|
|
353
|
+
xhr.open(method, url);
|
|
354
|
+
} else if ('withCredentials' in xhr) {
|
|
355
|
+
xhr.open(method, url, true);
|
|
356
|
+
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
|
357
|
+
} else {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
xhr._idx = this.requestIdx;
|
|
362
|
+
|
|
363
|
+
xhr.onload = function onLoad() {
|
|
364
|
+
log(
|
|
365
|
+
TYPE_DRIVER_EXTRA,
|
|
366
|
+
`XHRDriver::request::onload idx=${xhr._idx}, response=${this.responseText}`,
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
if (this.responseText.length > 0) {
|
|
370
|
+
success(self._parseResponse(this.responseText));
|
|
371
|
+
} else {
|
|
372
|
+
failure(this.responseText);
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
xhr.onerror = function onError() {
|
|
377
|
+
log(
|
|
378
|
+
TYPE_DRIVER_EXTRA,
|
|
379
|
+
`XHRDriver::request::onerror idx=${xhr._idx}, response=${this.responseText}`,
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
failure(this.responseText);
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
// XHR doesn't trigger onabort event in IE < 10
|
|
386
|
+
// attaching custom abort handler and execute
|
|
387
|
+
// it manually on each abort() call
|
|
388
|
+
xhr._onabort = () => {
|
|
389
|
+
log(
|
|
390
|
+
TYPE_DRIVER_EXTRA,
|
|
391
|
+
`XHRDriver::request::onabort idx=${xhr._idx}`,
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
abort();
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
return xhr;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
_parseResponse(response) {
|
|
401
|
+
const data = {};
|
|
402
|
+
const chunks = response.split('&');
|
|
403
|
+
|
|
404
|
+
for (let i = 0, l = chunks.length; i < l; i++) {
|
|
405
|
+
const [key, value] = chunks[i].split('=');
|
|
406
|
+
|
|
407
|
+
const normalisedValue = decodeURIComponent(value.replace('\0', ''));
|
|
408
|
+
|
|
409
|
+
if (key in data) {
|
|
410
|
+
if (data[key].constructor !== Array) {
|
|
411
|
+
data[key] = [data[key]];
|
|
412
|
+
}
|
|
413
|
+
data[key].push(normalisedValue);
|
|
414
|
+
} else {
|
|
415
|
+
data[key] = normalisedValue;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return data;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
_removeRequest(idx) {
|
|
423
|
+
log(TYPE_DRIVER_EXTRA, 'XHRDriver::removeRequest', idx);
|
|
424
|
+
|
|
425
|
+
if (Object.prototype.hasOwnProperty.call(this.requests, idx)) {
|
|
426
|
+
delete this.requests[idx];
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
connect() {
|
|
431
|
+
log(TYPE_DRIVER, 'XHRDriver::connect');
|
|
432
|
+
|
|
433
|
+
if (this.connected) {
|
|
434
|
+
log(
|
|
435
|
+
TYPE_DRIVER,
|
|
436
|
+
'XHRDriver::connect already been connected!',
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
this.connected = true;
|
|
443
|
+
|
|
444
|
+
this.trigger(XHRDriver.ON_CONNECTED);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
disconnect() {
|
|
448
|
+
log(TYPE_DRIVER, 'XHRDriver::disconnect');
|
|
449
|
+
|
|
450
|
+
if (this.connected) {
|
|
451
|
+
// abort all requests
|
|
452
|
+
for (const idx in this.requests) {
|
|
453
|
+
if (
|
|
454
|
+
Object.prototype.hasOwnProperty.call(this.requests, idx) &&
|
|
455
|
+
this.requests[idx].abort
|
|
456
|
+
) {
|
|
457
|
+
this.requests[idx].abort();
|
|
458
|
+
|
|
459
|
+
if (this.requests[idx]._onabort) {
|
|
460
|
+
this.requests[idx]._onabort();
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
this._removeRequest(idx);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
this.connected = false;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
this.trigger(XHRDriver.ON_DISCONNECTED);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
send(url, data, success = () => {}, failure = () => {}) {
|
|
474
|
+
log(TYPE_DRIVER, 'XHRDriver::send', data);
|
|
475
|
+
|
|
476
|
+
let xhr;
|
|
477
|
+
let retry = 1;
|
|
478
|
+
|
|
479
|
+
const send = () => {
|
|
480
|
+
// eslint-disable-next-line
|
|
481
|
+
xhr = this._request(url, onSuccess, onFailure, onAbort);
|
|
482
|
+
|
|
483
|
+
this.requests[xhr._idx] = xhr;
|
|
484
|
+
|
|
485
|
+
// fixes aborting requests in IE
|
|
486
|
+
setTimeout(() => {
|
|
487
|
+
xhr.send(data);
|
|
488
|
+
}, 0);
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
const onSuccess = (response) => {
|
|
492
|
+
log(TYPE_DRIVER, 'XHRDriver::success', data);
|
|
493
|
+
this._removeRequest(xhr._idx);
|
|
494
|
+
success(response);
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
const onFailure = (response) => {
|
|
498
|
+
log(TYPE_DRIVER, 'XHRDriver::failure, retry: ', retry);
|
|
499
|
+
this._removeRequest(xhr._idx);
|
|
500
|
+
if (retry <= this.config.request_retries) {
|
|
501
|
+
setTimeout(() => {
|
|
502
|
+
send();
|
|
503
|
+
retry++;
|
|
504
|
+
}, this.config.request_retry_delay * 1000);
|
|
505
|
+
} else {
|
|
506
|
+
failure(response);
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
const onAbort = () => {
|
|
511
|
+
log(TYPE_DRIVER, 'XHRDriver::abort', data);
|
|
512
|
+
this._removeRequest(xhr._idx);
|
|
513
|
+
failure();
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
send();
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
static hasSupport() {
|
|
520
|
+
return (
|
|
521
|
+
'XDomainRequest' in globals$1 || 'withCredentials' in new XMLHttpRequest()
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* eslint class-methods-use-this: "off" */
|
|
527
|
+
|
|
528
|
+
const globals = sdkUtil.getGlobal();
|
|
529
|
+
|
|
530
|
+
class WebSocketDriver extends Driver {
|
|
531
|
+
constructor() {
|
|
532
|
+
super();
|
|
533
|
+
|
|
534
|
+
this.websocket = null;
|
|
535
|
+
this.closeTimeout = null;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
_onMessage(e) {
|
|
539
|
+
log(TYPE_DRIVER, 'WebSocketDriver::onMessage', e.data);
|
|
540
|
+
this.trigger(WebSocketDriver.ON_MESSAGE, e.data);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
_onOpen() {
|
|
544
|
+
log(TYPE_DRIVER, 'WebSocketDriver::onOpen');
|
|
545
|
+
this.connected = true;
|
|
546
|
+
this.trigger(WebSocketDriver.ON_CONNECTED);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
_onClose() {
|
|
550
|
+
log(TYPE_DRIVER, 'WebSocketDriver::onClose');
|
|
551
|
+
this._disconnect();
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
_onError() {
|
|
555
|
+
log(TYPE_DRIVER, 'WebSocketDriver::onError');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
_disconnect() {
|
|
559
|
+
log(TYPE_DRIVER, 'WebSocketDriver::disconnect');
|
|
560
|
+
|
|
561
|
+
this.connected = false;
|
|
562
|
+
|
|
563
|
+
// reset handlers if websocket was created
|
|
564
|
+
if (this.websocket !== null) {
|
|
565
|
+
this.websocket.onmessage = () => {};
|
|
566
|
+
this.websocket.onopen = () => {};
|
|
567
|
+
this.websocket.onclose = () => {};
|
|
568
|
+
this.websocket.onerror = () => {};
|
|
569
|
+
this.websocket = null;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
clearTimeout(this.closeTimeout);
|
|
573
|
+
|
|
574
|
+
this.trigger(WebSocketDriver.ON_DISCONNECTED);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
connect(host, port, secure) {
|
|
578
|
+
if (this.connected) {
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
log(TYPE_DRIVER, 'WebSocketDriver::connect', host, port);
|
|
583
|
+
|
|
584
|
+
const url = `${secure ? 'wss' : 'ws'}://${host}:${port}/ws`;
|
|
585
|
+
|
|
586
|
+
this.websocket = new WebSocket(url);
|
|
587
|
+
this.websocket.onmessage = this._onMessage.bind(this);
|
|
588
|
+
this.websocket.onopen = this._onOpen.bind(this);
|
|
589
|
+
this.websocket.onclose = this._onClose.bind(this);
|
|
590
|
+
this.websocket.onerror = this._onError.bind(this);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
disconnect() {
|
|
594
|
+
log(TYPE_DRIVER, 'WebSocketDriver::disconnect');
|
|
595
|
+
|
|
596
|
+
if (this.connected) {
|
|
597
|
+
// ON_DISCONNECTED will be triggered at onClose event
|
|
598
|
+
this.websocket.close();
|
|
599
|
+
|
|
600
|
+
// websocket does not fire onclose if network connection is lost
|
|
601
|
+
// set timeout to force fire ON_DISCONNECTED event
|
|
602
|
+
this.closeTimeout = setTimeout(this._disconnect.bind(this), 750);
|
|
603
|
+
} else {
|
|
604
|
+
// disconnect instantly if websocket wasn't connected or still connecting
|
|
605
|
+
this._disconnect();
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
send(data, success = () => {}) {
|
|
610
|
+
log(TYPE_DRIVER, 'WebSocketDriver::send', data);
|
|
611
|
+
this.websocket.send(data);
|
|
612
|
+
success();
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
static hasSupport() {
|
|
616
|
+
return 'WebSocket' in globals;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const COMMAND_CONNECT = 'connect';
|
|
621
|
+
const COMMAND_PASS = 'pass';
|
|
622
|
+
const COMMAND_POLL = 'poll';
|
|
623
|
+
|
|
624
|
+
class ProxyTransport extends Transport {
|
|
625
|
+
constructor(config = {}) {
|
|
626
|
+
log(TYPE_TRANSPORT, 'ProxyTransport::constructor', config);
|
|
627
|
+
|
|
628
|
+
super(config);
|
|
629
|
+
|
|
630
|
+
this.driver = config.driver || null;
|
|
631
|
+
this.host = config.host || null;
|
|
632
|
+
this.port = config.port || null;
|
|
633
|
+
this.secure = config.secure || false;
|
|
634
|
+
|
|
635
|
+
/*
|
|
636
|
+
* Proxy properties
|
|
637
|
+
* host and port should be always preserved on connect and reconnect
|
|
638
|
+
* drop proxyIp, childId and clientId on reconnect and disconnect
|
|
639
|
+
*/
|
|
640
|
+
|
|
641
|
+
this.proxyIp = null;
|
|
642
|
+
this.childId = null;
|
|
643
|
+
this.clientId = null;
|
|
644
|
+
this.sessionId = null;
|
|
645
|
+
|
|
646
|
+
this.driver.bind(Driver.ON_READY, this._handleDriverReady.bind(this));
|
|
647
|
+
this.driver.bind(
|
|
648
|
+
Driver.ON_CONNECTED,
|
|
649
|
+
this._handleDriverConnected.bind(this),
|
|
650
|
+
);
|
|
651
|
+
this.driver.bind(
|
|
652
|
+
Driver.ON_DISCONNECTED,
|
|
653
|
+
this._handleDriverDisconnected.bind(this),
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
_url() {
|
|
658
|
+
return (
|
|
659
|
+
`${this.secure ? 'https' : 'http'}://` +
|
|
660
|
+
`${this.proxyIp ? this.proxyIp : this.host}:` +
|
|
661
|
+
`${this.port}/` +
|
|
662
|
+
`${this.childId !== null ? `${this.childId}/` : ''}` +
|
|
663
|
+
`?_r=${new Date().getTime()}`
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
_request(params = '', success = () => {}, failure = () => {}) {
|
|
668
|
+
const self = this;
|
|
669
|
+
|
|
670
|
+
const onSuccess = (response) => {
|
|
671
|
+
// fire ON_MESSAGE event unless sscp message is empty
|
|
672
|
+
if (response.sscp.constructor === String) {
|
|
673
|
+
response.sscp = [response.sscp];
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
for (let i = 0, l = response.sscp.length; i < l; i++) {
|
|
677
|
+
if (response.sscp[i] !== '') {
|
|
678
|
+
self.trigger(ProxyTransport.ON_MESSAGE, response.sscp[i]);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
success(response);
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
const onFailure = () => {
|
|
686
|
+
switch (self.state) {
|
|
687
|
+
case ProxyTransport.STATE_CONNECTED:
|
|
688
|
+
self.state = ProxyTransport.STATE_DISCONNECTING;
|
|
689
|
+
self.trigger(ProxyTransport.ON_CONNECT_FAILED);
|
|
690
|
+
break;
|
|
691
|
+
case ProxyTransport.STATE_CONNECTING:
|
|
692
|
+
self.state = ProxyTransport.STATE_DISCONNECTING;
|
|
693
|
+
self.trigger(ProxyTransport.ON_CONNECT_FAILED);
|
|
694
|
+
break;
|
|
695
|
+
case ProxyTransport.STATE_DISCONNECTING:
|
|
696
|
+
self.state = ProxyTransport.STATE_DISCONNECTED;
|
|
697
|
+
self.trigger(ProxyTransport.ON_DISCONNECTED);
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
failure();
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
this.driver.send(this._url(), params, onSuccess, onFailure);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
_poll() {
|
|
708
|
+
const params =
|
|
709
|
+
`command=${COMMAND_POLL}` +
|
|
710
|
+
`&clientid=${this.clientId}` +
|
|
711
|
+
`&sid=${this.sessionId}`;
|
|
712
|
+
|
|
713
|
+
this._request(params, this._poll.bind(this));
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
_connect() {
|
|
717
|
+
const self = this;
|
|
718
|
+
|
|
719
|
+
const onSuccess = (response) => {
|
|
720
|
+
self.proxyIp = response.proxy;
|
|
721
|
+
self.clientId = parseInt(response.clientid, 10);
|
|
722
|
+
self.childId = parseInt(response.childid, 10);
|
|
723
|
+
self.sessionId = response.sid;
|
|
724
|
+
|
|
725
|
+
self.state = ProxyTransport.STATE_CONNECTED;
|
|
726
|
+
|
|
727
|
+
self.trigger(ProxyTransport.ON_CONNECTED);
|
|
728
|
+
|
|
729
|
+
self._poll();
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
const onFailure = () => {
|
|
733
|
+
self.state = ProxyTransport.STATE_DISCONNECTED;
|
|
734
|
+
self.trigger(ProxyTransport.ON_CONNECT_FAILED);
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
const params = `command=${COMMAND_CONNECT}`;
|
|
738
|
+
|
|
739
|
+
this._request(params, onSuccess, onFailure);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
_handleDriverReady() {
|
|
743
|
+
this.trigger(ProxyTransport.ON_READY);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
_handleDriverConnected() {
|
|
747
|
+
this._connect();
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
_handleDriverDisconnected() {
|
|
751
|
+
log(
|
|
752
|
+
TYPE_TRANSPORT,
|
|
753
|
+
'ProxyTransport::handleDriverDisconnected',
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
const { state } = this;
|
|
757
|
+
|
|
758
|
+
this.state = ProxyTransport.STATE_DISCONNECTED;
|
|
759
|
+
|
|
760
|
+
switch (state) {
|
|
761
|
+
case ProxyTransport.STATE_CONNECTED:
|
|
762
|
+
this.trigger(ProxyTransport.ON_CONNECT_LOST);
|
|
763
|
+
break;
|
|
764
|
+
case ProxyTransport.STATE_CONNECTING:
|
|
765
|
+
this.trigger(ProxyTransport.ON_CONNECT_FAILED);
|
|
766
|
+
break;
|
|
767
|
+
case ProxyTransport.STATE_DISCONNECTING:
|
|
768
|
+
this.trigger(ProxyTransport.ON_DISCONNECTED);
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
send(sscp, success = () => {}, failure = () => {}) {
|
|
774
|
+
log(TYPE_TRANSPORT, 'ProxyTransport::send', sscp);
|
|
775
|
+
|
|
776
|
+
const params =
|
|
777
|
+
`command=${COMMAND_PASS}` +
|
|
778
|
+
`&clientid=${this.clientId}` +
|
|
779
|
+
`&sscp=${sscp}` +
|
|
780
|
+
`&sid=${this.sessionId}`;
|
|
781
|
+
|
|
782
|
+
this._request(params, success, failure);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
connect() {
|
|
786
|
+
log(
|
|
787
|
+
TYPE_TRANSPORT,
|
|
788
|
+
'ProxyTransport::connect',
|
|
789
|
+
this.host,
|
|
790
|
+
this.port,
|
|
791
|
+
);
|
|
792
|
+
|
|
793
|
+
this.state = ProxyTransport.STATE_CONNECTING;
|
|
794
|
+
this.driver.connect();
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
disconnect() {
|
|
798
|
+
log(TYPE_TRANSPORT, 'ProxyTransport::disconnect');
|
|
799
|
+
|
|
800
|
+
// drop proxy settings
|
|
801
|
+
this.proxyIp = null;
|
|
802
|
+
this.childId = null;
|
|
803
|
+
this.sessionId = null;
|
|
804
|
+
this.state = ProxyTransport.STATE_DISCONNECTING;
|
|
805
|
+
|
|
806
|
+
this.driver.disconnect();
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
init() {
|
|
810
|
+
log(TYPE_TRANSPORT, 'ProxyTransport::init');
|
|
811
|
+
|
|
812
|
+
this.driver.init();
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
class SocketTransport extends Transport {
|
|
817
|
+
constructor(config = {}) {
|
|
818
|
+
log(TYPE_TRANSPORT, 'SocketTransport::constructor', config);
|
|
819
|
+
|
|
820
|
+
super();
|
|
821
|
+
|
|
822
|
+
this.driver = config.driver || null;
|
|
823
|
+
this.host = config.host || null;
|
|
824
|
+
this.port = config.port || null;
|
|
825
|
+
this.secure = config.secure || false;
|
|
826
|
+
|
|
827
|
+
this.driver.bind(Driver.ON_READY, this._handleDriverReady.bind(this));
|
|
828
|
+
this.driver.bind(Driver.ON_MESSAGE, this._handleDriverMessage.bind(this));
|
|
829
|
+
this.driver.bind(
|
|
830
|
+
Driver.ON_CONNECTED,
|
|
831
|
+
this._handleDriverConnected.bind(this),
|
|
832
|
+
);
|
|
833
|
+
this.driver.bind(
|
|
834
|
+
Driver.ON_DISCONNECTED,
|
|
835
|
+
this._handleDriverDisconnected.bind(this),
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
_handleDriverReady() {
|
|
840
|
+
log(TYPE_TRANSPORT, 'SocketTransport::_handleDriverReady');
|
|
841
|
+
|
|
842
|
+
this.trigger(SocketTransport.ON_READY);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
_handleDriverMessage(message) {
|
|
846
|
+
log(TYPE_TRANSPORT, 'SocketTransport::handleDriverMessage');
|
|
847
|
+
|
|
848
|
+
this.trigger(SocketTransport.ON_MESSAGE, message);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
_handleDriverConnected() {
|
|
852
|
+
log(TYPE_TRANSPORT, 'SocketTransport::handleDriverConnected');
|
|
853
|
+
|
|
854
|
+
this.state = SocketTransport.STATE_CONNECTED;
|
|
855
|
+
this.trigger(SocketTransport.ON_CONNECTED);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
_handleDriverDisconnected() {
|
|
859
|
+
log(
|
|
860
|
+
TYPE_TRANSPORT,
|
|
861
|
+
'SocketTransport::handleDriverDisconnected',
|
|
862
|
+
);
|
|
863
|
+
|
|
864
|
+
const { state } = this;
|
|
865
|
+
|
|
866
|
+
this.state = SocketTransport.STATE_DISCONNECTED;
|
|
867
|
+
|
|
868
|
+
switch (state) {
|
|
869
|
+
case SocketTransport.STATE_CONNECTED:
|
|
870
|
+
this.trigger(SocketTransport.ON_CONNECT_LOST);
|
|
871
|
+
break;
|
|
872
|
+
case SocketTransport.STATE_CONNECTING:
|
|
873
|
+
this.trigger(SocketTransport.ON_CONNECT_FAILED);
|
|
874
|
+
break;
|
|
875
|
+
case SocketTransport.STATE_DISCONNECTING:
|
|
876
|
+
this.trigger(SocketTransport.ON_DISCONNECTED);
|
|
877
|
+
break;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
send(sscp, success = () => {}, failure = () => {}) {
|
|
882
|
+
log(TYPE_TRANSPORT, 'SocketTransport::send', sscp);
|
|
883
|
+
this.driver.send(sscp, success, failure);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
connect() {
|
|
887
|
+
log(
|
|
888
|
+
TYPE_TRANSPORT,
|
|
889
|
+
'SocketTransport::connect',
|
|
890
|
+
this.host,
|
|
891
|
+
this.port,
|
|
892
|
+
);
|
|
893
|
+
this.state = SocketTransport.STATE_CONNECTING;
|
|
894
|
+
this.driver.connect(this.host, this.port, this.secure);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
disconnect() {
|
|
898
|
+
log(TYPE_TRANSPORT, 'SocketTransport::disconnect');
|
|
899
|
+
this.state = SocketTransport.STATE_DISCONNECTING;
|
|
900
|
+
this.driver.disconnect();
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
init() {
|
|
904
|
+
log(TYPE_TRANSPORT, 'SocketTransport::init');
|
|
905
|
+
this.driver.init();
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
const METHOD_PROXY = 'proxy';
|
|
910
|
+
const METHOD_WEBSOCKET = 'websocket';
|
|
911
|
+
|
|
912
|
+
class TransportManager extends sdkUtil.Emitter {
|
|
913
|
+
constructor() {
|
|
914
|
+
super();
|
|
915
|
+
|
|
916
|
+
this.trigger = this.emit;
|
|
917
|
+
this.bind = this.on;
|
|
918
|
+
this.unbind = this.off;
|
|
919
|
+
|
|
920
|
+
this.ON_READY = 'ready';
|
|
921
|
+
this.config = null;
|
|
922
|
+
this.idx = 0;
|
|
923
|
+
|
|
924
|
+
// list of connection types pairs: transport - driver
|
|
925
|
+
this.methods = {};
|
|
926
|
+
this.transports = {};
|
|
927
|
+
this.loaded = 0;
|
|
928
|
+
this.sequence = [];
|
|
929
|
+
this.allowed = [];
|
|
930
|
+
this.secure = true;
|
|
931
|
+
|
|
932
|
+
// Guarding the use of the window object in environments where it might
|
|
933
|
+
// not be available, such as during server - side rendering in a framework
|
|
934
|
+
// like Next.js
|
|
935
|
+
if (typeof window !== 'undefined') {
|
|
936
|
+
this.secure = window.location.protocol.indexOf('https') === 0;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// list of connection methods which where unsuccessful
|
|
940
|
+
this.unsuccessful = [];
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
_instantiate() {
|
|
944
|
+
log(TYPE_MANAGER, 'TransportManager::instantiate');
|
|
945
|
+
|
|
946
|
+
// instantiate all transports
|
|
947
|
+
this.allowed.forEach((method) => {
|
|
948
|
+
const config = this._getMethodConfig(method);
|
|
949
|
+
|
|
950
|
+
// pick the random host
|
|
951
|
+
const host =
|
|
952
|
+
config.hosts[Math.floor(Math.random() * config.hosts.length)];
|
|
953
|
+
|
|
954
|
+
const TransportKlass = this.methods[method].transport;
|
|
955
|
+
const DriverKlass = this.methods[method].driver;
|
|
956
|
+
|
|
957
|
+
const transport = new TransportKlass({
|
|
958
|
+
driver: new DriverKlass(config.driver || {}),
|
|
959
|
+
host,
|
|
960
|
+
port: this.secure ? config.secure_port : config.port,
|
|
961
|
+
secure: this.secure,
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
this.transports[method] = transport;
|
|
965
|
+
|
|
966
|
+
transport.bind(Transport.ON_READY, this._handleTransportReady.bind(this));
|
|
967
|
+
}, this);
|
|
968
|
+
|
|
969
|
+
// initialise all transports
|
|
970
|
+
for (const method in this.transports) {
|
|
971
|
+
if (Object.prototype.hasOwnProperty.call(this.transports, method)) {
|
|
972
|
+
this.transports[method].init();
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
_getMethodConfig(method) {
|
|
978
|
+
return this.config.methods.find((item) => item.type === method);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
_handleTransportReady() {
|
|
982
|
+
this.loaded += 1;
|
|
983
|
+
|
|
984
|
+
if (this.loaded === this.allowed.length) {
|
|
985
|
+
this.trigger(this.ON_READY);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
current() {
|
|
990
|
+
return this.transports[this.allowed[this.idx]];
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
next() {
|
|
994
|
+
this.idx += 1;
|
|
995
|
+
|
|
996
|
+
if (this.idx >= this.allowed.length) {
|
|
997
|
+
return false;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
return this.current();
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
reset() {
|
|
1004
|
+
this.allowed = [];
|
|
1005
|
+
this.unsuccessful = [];
|
|
1006
|
+
|
|
1007
|
+
// gather all methods in one array in correct connection sequence
|
|
1008
|
+
for (let i = 0, l = this.sequence.length; i < l; i += 1) {
|
|
1009
|
+
// shift method's idx by the value of the current method idx
|
|
1010
|
+
const method = this.sequence[(i + this.idx) % l];
|
|
1011
|
+
|
|
1012
|
+
if (this.methods[method].driver.hasSupport()) {
|
|
1013
|
+
this.allowed.push(method);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
this.idx = 0;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
addUnsuccessful(transport) {
|
|
1021
|
+
for (const method in this.transports) {
|
|
1022
|
+
if (
|
|
1023
|
+
Object.prototype.hasOwnProperty.call(this.transports, method) &&
|
|
1024
|
+
this.transports[method] === transport
|
|
1025
|
+
) {
|
|
1026
|
+
this.unsuccessful.push(method);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
init(config = {}) {
|
|
1032
|
+
this.config = config;
|
|
1033
|
+
this.idx = 0;
|
|
1034
|
+
this.loaded = 0;
|
|
1035
|
+
this.sequence = [];
|
|
1036
|
+
this.secure = config.forceSecure === true ? true : this.secure;
|
|
1037
|
+
|
|
1038
|
+
this.methods[METHOD_PROXY] = {
|
|
1039
|
+
driver: XHRDriver,
|
|
1040
|
+
transport: ProxyTransport,
|
|
1041
|
+
};
|
|
1042
|
+
this.methods[METHOD_WEBSOCKET] = {
|
|
1043
|
+
driver: WebSocketDriver,
|
|
1044
|
+
transport: SocketTransport,
|
|
1045
|
+
};
|
|
1046
|
+
|
|
1047
|
+
if (ENMASSE_OVERRIDE_METHODS) {
|
|
1048
|
+
this.sequence = ENMASSE_OVERRIDE_METHODS;
|
|
1049
|
+
} else {
|
|
1050
|
+
this.config.methods.forEach(
|
|
1051
|
+
(method) => this.sequence.push(method.type),
|
|
1052
|
+
this,
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// remove unsupported methods
|
|
1057
|
+
/* eslint-disable */
|
|
1058
|
+
this.sequence = this.sequence.filter((item) =>
|
|
1059
|
+
Object.prototype.hasOwnProperty.call(this.methods, item),
|
|
1060
|
+
);
|
|
1061
|
+
/* eslint-enable */
|
|
1062
|
+
|
|
1063
|
+
this.reset();
|
|
1064
|
+
|
|
1065
|
+
this._instantiate();
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
var TransportManager$1 = new TransportManager();
|
|
1070
|
+
|
|
1071
|
+
/* eslint @typescript-eslint/no-use-before-define: ["error", { "variables": false }] */
|
|
1072
|
+
|
|
1073
|
+
const ConnectionManager = (() => {
|
|
1074
|
+
const self = new sdkUtil.Emitter();
|
|
1075
|
+
|
|
1076
|
+
self.trigger = self.emit;
|
|
1077
|
+
self.bind = self.on;
|
|
1078
|
+
self.unbind = self.off;
|
|
1079
|
+
|
|
1080
|
+
/*
|
|
1081
|
+
* Constants
|
|
1082
|
+
*/
|
|
1083
|
+
const CONNECT_DELAYS = [0, 3, 5, 10, 20, 30, 45, 60];
|
|
1084
|
+
|
|
1085
|
+
/*
|
|
1086
|
+
* States
|
|
1087
|
+
*/
|
|
1088
|
+
self.STATE_DISCONNECTED = 'state_disconnected';
|
|
1089
|
+
self.STATE_DISCONNECTING = 'state_disconnecting';
|
|
1090
|
+
self.STATE_CONNECTING = 'state_connecting';
|
|
1091
|
+
self.STATE_CONNECTED = 'state_connected';
|
|
1092
|
+
|
|
1093
|
+
/*
|
|
1094
|
+
* Events
|
|
1095
|
+
*/
|
|
1096
|
+
self.ON_MESSAGE = 'message';
|
|
1097
|
+
self.ON_STATE = 'state';
|
|
1098
|
+
|
|
1099
|
+
/*
|
|
1100
|
+
* Private variables
|
|
1101
|
+
*/
|
|
1102
|
+
let config = null;
|
|
1103
|
+
let state = self.STATE_DISCONNECTED;
|
|
1104
|
+
let transport = null;
|
|
1105
|
+
let attempt = 1;
|
|
1106
|
+
|
|
1107
|
+
// Timestamp to track when the app was backgrounded
|
|
1108
|
+
let backgroundedAt = null;
|
|
1109
|
+
|
|
1110
|
+
const inactivityTimeout = {
|
|
1111
|
+
start() {
|
|
1112
|
+
log(
|
|
1113
|
+
TYPE_MANAGER_EXTRA,
|
|
1114
|
+
'ConnectionManager::inactivityTimeout::start',
|
|
1115
|
+
);
|
|
1116
|
+
|
|
1117
|
+
const stamp = now();
|
|
1118
|
+
|
|
1119
|
+
this.interval = setInterval(() => {
|
|
1120
|
+
if (now() - stamp >= config.inactivity_timeout) {
|
|
1121
|
+
this.resolve();
|
|
1122
|
+
}
|
|
1123
|
+
}, 1000);
|
|
1124
|
+
},
|
|
1125
|
+
|
|
1126
|
+
stop() {
|
|
1127
|
+
log(
|
|
1128
|
+
TYPE_MANAGER_EXTRA,
|
|
1129
|
+
'ConnectionManager::inactivityTimeout::stop',
|
|
1130
|
+
);
|
|
1131
|
+
|
|
1132
|
+
clearInterval(this.interval);
|
|
1133
|
+
},
|
|
1134
|
+
|
|
1135
|
+
reset() {
|
|
1136
|
+
log(
|
|
1137
|
+
TYPE_MANAGER_EXTRA,
|
|
1138
|
+
'ConnectionManager::inactivityTimeout::reset',
|
|
1139
|
+
);
|
|
1140
|
+
|
|
1141
|
+
this.stop();
|
|
1142
|
+
this.start();
|
|
1143
|
+
},
|
|
1144
|
+
|
|
1145
|
+
resolve() {
|
|
1146
|
+
log(
|
|
1147
|
+
TYPE_MANAGER_EXTRA,
|
|
1148
|
+
'ConnectionManager::inactivityTimeout::resolve',
|
|
1149
|
+
);
|
|
1150
|
+
|
|
1151
|
+
disconnectingOnConnectLost();
|
|
1152
|
+
},
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
const connectTimeout = {
|
|
1156
|
+
start() {
|
|
1157
|
+
log(
|
|
1158
|
+
TYPE_MANAGER_EXTRA,
|
|
1159
|
+
'ConnectionManager::connectTimeout::start',
|
|
1160
|
+
);
|
|
1161
|
+
|
|
1162
|
+
this.timeout = setTimeout(() => {
|
|
1163
|
+
this.resolve();
|
|
1164
|
+
}, config.connect_timeout * 1000);
|
|
1165
|
+
},
|
|
1166
|
+
|
|
1167
|
+
stop() {
|
|
1168
|
+
log(
|
|
1169
|
+
TYPE_MANAGER_EXTRA,
|
|
1170
|
+
'ConnectionManager::connectTimeout::stop',
|
|
1171
|
+
);
|
|
1172
|
+
|
|
1173
|
+
clearTimeout(this.timeout);
|
|
1174
|
+
},
|
|
1175
|
+
|
|
1176
|
+
resolve() {
|
|
1177
|
+
log(
|
|
1178
|
+
TYPE_MANAGER_EXTRA,
|
|
1179
|
+
'ConnectionManager::connectTimeout::resolve',
|
|
1180
|
+
);
|
|
1181
|
+
|
|
1182
|
+
disconnectingOnConnectFailed();
|
|
1183
|
+
},
|
|
1184
|
+
};
|
|
1185
|
+
|
|
1186
|
+
const connectDelay = {
|
|
1187
|
+
active: false,
|
|
1188
|
+
|
|
1189
|
+
start(delay) {
|
|
1190
|
+
log(
|
|
1191
|
+
TYPE_MANAGER_EXTRA,
|
|
1192
|
+
'ConnectionManager::connectDelay::start',
|
|
1193
|
+
);
|
|
1194
|
+
|
|
1195
|
+
this.active = true;
|
|
1196
|
+
this.timeout = setTimeout(() => {
|
|
1197
|
+
this.resolve();
|
|
1198
|
+
}, delay * 1000);
|
|
1199
|
+
},
|
|
1200
|
+
|
|
1201
|
+
stop() {
|
|
1202
|
+
log(
|
|
1203
|
+
TYPE_MANAGER_EXTRA,
|
|
1204
|
+
'ConnectionManager::connectDelay::stop',
|
|
1205
|
+
);
|
|
1206
|
+
|
|
1207
|
+
this.active = false;
|
|
1208
|
+
clearTimeout(this.timeout);
|
|
1209
|
+
},
|
|
1210
|
+
|
|
1211
|
+
resolve() {
|
|
1212
|
+
log(
|
|
1213
|
+
TYPE_MANAGER_EXTRA,
|
|
1214
|
+
'ConnectionManager::connectDelay::resolve',
|
|
1215
|
+
);
|
|
1216
|
+
|
|
1217
|
+
this.stop();
|
|
1218
|
+
connect();
|
|
1219
|
+
},
|
|
1220
|
+
};
|
|
1221
|
+
|
|
1222
|
+
const initTransport = (newTransport) => {
|
|
1223
|
+
log(TYPE_MANAGER, 'ConnectionManager::initTransport');
|
|
1224
|
+
|
|
1225
|
+
transport = newTransport;
|
|
1226
|
+
|
|
1227
|
+
transport.bind(Transport.ON_MESSAGE, handleTransportMessage);
|
|
1228
|
+
transport.bind(Transport.ON_CONNECTED, handleTransportConnected);
|
|
1229
|
+
transport.bind(Transport.ON_CONNECT_FAILED, handleTransportConnectFailed);
|
|
1230
|
+
transport.bind(Transport.ON_CONNECT_LOST, handleTransportConnectLost);
|
|
1231
|
+
transport.bind(Transport.ON_DISCONNECTED, handleTransportDisconnected);
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1234
|
+
const teardownTransport = () => {
|
|
1235
|
+
log(TYPE_MANAGER, 'ConnectionManager::teardownTransport');
|
|
1236
|
+
|
|
1237
|
+
if (transport === null) {
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
transport.unbind(Transport.ON_MESSAGE, handleTransportMessage);
|
|
1242
|
+
transport.unbind(Transport.ON_CONNECTED, handleTransportConnected);
|
|
1243
|
+
transport.unbind(Transport.ON_CONNECT_FAILED, handleTransportConnectFailed);
|
|
1244
|
+
transport.unbind(Transport.ON_CONNECT_LOST, handleTransportConnectLost);
|
|
1245
|
+
transport.unbind(Transport.ON_DISCONNECTED, handleTransportDisconnected);
|
|
1246
|
+
|
|
1247
|
+
transport = null;
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
const handleTransportMessage = (message) => {
|
|
1251
|
+
log(
|
|
1252
|
+
TYPE_MANAGER,
|
|
1253
|
+
'ConnectionManager::handleTransportMessage',
|
|
1254
|
+
message,
|
|
1255
|
+
);
|
|
1256
|
+
|
|
1257
|
+
const messages = message.split('\0');
|
|
1258
|
+
|
|
1259
|
+
for (let i = 0; i < messages.length; i += 1) {
|
|
1260
|
+
if (messages[i].length > 0) {
|
|
1261
|
+
inactivityTimeout.reset();
|
|
1262
|
+
log(
|
|
1263
|
+
TYPE_MANAGER,
|
|
1264
|
+
'ConnectionManager::handleTransportMessage',
|
|
1265
|
+
'send upstream m:',
|
|
1266
|
+
messages[i],
|
|
1267
|
+
);
|
|
1268
|
+
self.trigger(self.ON_MESSAGE, messages[i]);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
const handleTransportConnected = () => {
|
|
1274
|
+
log(
|
|
1275
|
+
TYPE_MANAGER,
|
|
1276
|
+
'ConnectionManager::handleTransportConnected',
|
|
1277
|
+
);
|
|
1278
|
+
setStateToConnected();
|
|
1279
|
+
};
|
|
1280
|
+
|
|
1281
|
+
const handleTransportConnectFailed = () => {
|
|
1282
|
+
log(
|
|
1283
|
+
TYPE_MANAGER,
|
|
1284
|
+
'ConnectionManager::handleTransportConnectFailed',
|
|
1285
|
+
);
|
|
1286
|
+
disconnectingOnConnectFailed();
|
|
1287
|
+
};
|
|
1288
|
+
|
|
1289
|
+
const handleTransportConnectLost = () => {
|
|
1290
|
+
log(
|
|
1291
|
+
TYPE_MANAGER,
|
|
1292
|
+
'ConnectionManager::handleTransportConnectLost',
|
|
1293
|
+
);
|
|
1294
|
+
disconnectingOnConnectLost();
|
|
1295
|
+
};
|
|
1296
|
+
|
|
1297
|
+
const handleTransportDisconnected = () => {
|
|
1298
|
+
log(
|
|
1299
|
+
TYPE_MANAGER,
|
|
1300
|
+
'ConnectionManager::handleTransportDisconnected',
|
|
1301
|
+
);
|
|
1302
|
+
|
|
1303
|
+
switch (state) {
|
|
1304
|
+
case self.STATE_CONNECTED:
|
|
1305
|
+
disconnectedOnConnectLost();
|
|
1306
|
+
break;
|
|
1307
|
+
case self.STATE_CONNECTING:
|
|
1308
|
+
disconnectedOnConnectFailed();
|
|
1309
|
+
break;
|
|
1310
|
+
case self.STATE_DISCONNECTING:
|
|
1311
|
+
setStateToDisconnected();
|
|
1312
|
+
break;
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
|
|
1316
|
+
const disconnectingOnConnectFailed = () => {
|
|
1317
|
+
log(
|
|
1318
|
+
TYPE_MANAGER,
|
|
1319
|
+
'ConnectionManager::disconnectingOnConnectFailed()',
|
|
1320
|
+
);
|
|
1321
|
+
|
|
1322
|
+
disconnect();
|
|
1323
|
+
};
|
|
1324
|
+
|
|
1325
|
+
const disconnectingOnConnectLost = () => {
|
|
1326
|
+
log(
|
|
1327
|
+
TYPE_MANAGER,
|
|
1328
|
+
'ConnectionManager::disconnectingOnConnectLost()',
|
|
1329
|
+
);
|
|
1330
|
+
|
|
1331
|
+
disconnect();
|
|
1332
|
+
};
|
|
1333
|
+
|
|
1334
|
+
const disconnectedOnConnectLost = () => {
|
|
1335
|
+
log(
|
|
1336
|
+
TYPE_MANAGER,
|
|
1337
|
+
'ConnectionManager::disconnectedOnConnectLost()',
|
|
1338
|
+
);
|
|
1339
|
+
|
|
1340
|
+
teardownTransport();
|
|
1341
|
+
|
|
1342
|
+
// automatically reconnect
|
|
1343
|
+
setStateToConnecting();
|
|
1344
|
+
};
|
|
1345
|
+
|
|
1346
|
+
const disconnectedOnConnectFailed = () => {
|
|
1347
|
+
log(
|
|
1348
|
+
TYPE_MANAGER,
|
|
1349
|
+
'ConnectionManager::disconnectedOnConnectFailed()',
|
|
1350
|
+
);
|
|
1351
|
+
|
|
1352
|
+
TransportManager$1.addUnsuccessful(transport);
|
|
1353
|
+
|
|
1354
|
+
teardownTransport();
|
|
1355
|
+
|
|
1356
|
+
if (TransportManager$1.next() === false) {
|
|
1357
|
+
setStateToConnecting();
|
|
1358
|
+
} else {
|
|
1359
|
+
connect();
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
|
|
1363
|
+
const setStateToConnecting = () => {
|
|
1364
|
+
log(
|
|
1365
|
+
TYPE_MANAGER,
|
|
1366
|
+
'ConnectionManager::setStateToConnecting()',
|
|
1367
|
+
);
|
|
1368
|
+
|
|
1369
|
+
let delay;
|
|
1370
|
+
|
|
1371
|
+
if (attempt >= CONNECT_DELAYS.length) {
|
|
1372
|
+
delay = CONNECT_DELAYS[CONNECT_DELAYS.length - 1];
|
|
1373
|
+
} else {
|
|
1374
|
+
delay = CONNECT_DELAYS[attempt - 1];
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
state = self.STATE_CONNECTING;
|
|
1378
|
+
self.trigger(self.ON_STATE, state, attempt, delay);
|
|
1379
|
+
|
|
1380
|
+
TransportManager$1.reset();
|
|
1381
|
+
|
|
1382
|
+
attempt += 1;
|
|
1383
|
+
connectDelay.start(delay);
|
|
1384
|
+
};
|
|
1385
|
+
|
|
1386
|
+
const setStateToConnected = () => {
|
|
1387
|
+
log(TYPE_MANAGER, 'ConnectionManager::setStateToConnected()');
|
|
1388
|
+
|
|
1389
|
+
attempt = 1;
|
|
1390
|
+
TransportManager$1.reset();
|
|
1391
|
+
inactivityTimeout.reset();
|
|
1392
|
+
connectTimeout.stop();
|
|
1393
|
+
connectDelay.stop();
|
|
1394
|
+
|
|
1395
|
+
state = self.STATE_CONNECTED;
|
|
1396
|
+
self.trigger(self.ON_STATE, state);
|
|
1397
|
+
};
|
|
1398
|
+
|
|
1399
|
+
const setStateToDisconnecting = () => {
|
|
1400
|
+
log(
|
|
1401
|
+
TYPE_MANAGER,
|
|
1402
|
+
'ConnectionManager::setStateToDisconnecting()',
|
|
1403
|
+
);
|
|
1404
|
+
|
|
1405
|
+
state = self.STATE_DISCONNECTING;
|
|
1406
|
+
self.trigger(self.ON_STATE, state);
|
|
1407
|
+
|
|
1408
|
+
disconnect();
|
|
1409
|
+
};
|
|
1410
|
+
|
|
1411
|
+
const setStateToDisconnected = () => {
|
|
1412
|
+
log(
|
|
1413
|
+
TYPE_MANAGER,
|
|
1414
|
+
'ConnectionManager::setStateToDisconnected()',
|
|
1415
|
+
);
|
|
1416
|
+
|
|
1417
|
+
attempt = 1;
|
|
1418
|
+
teardownTransport();
|
|
1419
|
+
TransportManager$1.reset();
|
|
1420
|
+
|
|
1421
|
+
state = self.STATE_DISCONNECTED;
|
|
1422
|
+
self.trigger(self.ON_STATE, state);
|
|
1423
|
+
};
|
|
1424
|
+
|
|
1425
|
+
const connect = () => {
|
|
1426
|
+
if (state === self.STATE_CONNECTING) {
|
|
1427
|
+
connectTimeout.start();
|
|
1428
|
+
initTransport(TransportManager$1.current());
|
|
1429
|
+
transport.connect();
|
|
1430
|
+
}
|
|
1431
|
+
};
|
|
1432
|
+
|
|
1433
|
+
const disconnect = () => {
|
|
1434
|
+
inactivityTimeout.stop();
|
|
1435
|
+
connectTimeout.stop();
|
|
1436
|
+
connectDelay.stop();
|
|
1437
|
+
|
|
1438
|
+
if (transport) {
|
|
1439
|
+
transport.disconnect();
|
|
1440
|
+
} else {
|
|
1441
|
+
setStateToDisconnected();
|
|
1442
|
+
}
|
|
1443
|
+
};
|
|
1444
|
+
|
|
1445
|
+
/**
|
|
1446
|
+
* Handles changes in the document's visibility state (visible/hidden).
|
|
1447
|
+
*
|
|
1448
|
+
* - Tracks when the document is backgrounded by recording the timestamp.
|
|
1449
|
+
* - When the document becomes visible again, checks if the time spent in the background
|
|
1450
|
+
* exceeds a configured timeout. If it does, the connection is disconnected.
|
|
1451
|
+
* - Ensures actions are only taken if necessary, based on the current connection state
|
|
1452
|
+
* and whether the page was previously backgrounded.
|
|
1453
|
+
*
|
|
1454
|
+
* Note on Safari (ios and desktop) and Firefox quirk: visibilitychange event is fired
|
|
1455
|
+
* immidiately when the page is loaded, even if the page is visible.
|
|
1456
|
+
*/
|
|
1457
|
+
const handleVisibilityChange = () => {
|
|
1458
|
+
log(
|
|
1459
|
+
TYPE_MANAGER,
|
|
1460
|
+
'ConnectionManager::handleVisibilityChange()',
|
|
1461
|
+
document.visibilityState,
|
|
1462
|
+
);
|
|
1463
|
+
|
|
1464
|
+
switch (document.visibilityState) {
|
|
1465
|
+
case 'visible':
|
|
1466
|
+
if (backgroundedAt === null) {
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
if (state !== self.STATE_CONNECTED) {
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
if (Date.now() - backgroundedAt > config.background_timeout * 1000) {
|
|
1475
|
+
log(
|
|
1476
|
+
TYPE_MANAGER,
|
|
1477
|
+
'ConnectionManager::handleVisibilityChange()',
|
|
1478
|
+
'disconnecting due to background timeout',
|
|
1479
|
+
);
|
|
1480
|
+
|
|
1481
|
+
disconnect();
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
backgroundedAt = null;
|
|
1485
|
+
break;
|
|
1486
|
+
case 'hidden':
|
|
1487
|
+
backgroundedAt = Date.now();
|
|
1488
|
+
break;
|
|
1489
|
+
}
|
|
1490
|
+
};
|
|
1491
|
+
|
|
1492
|
+
const handleNetworkStatus = () => {
|
|
1493
|
+
if (!navigator.onLine && state === self.STATE_CONNECTED) {
|
|
1494
|
+
log(
|
|
1495
|
+
TYPE_MANAGER,
|
|
1496
|
+
'ConnectionManager::handleNetworkStatus()',
|
|
1497
|
+
'disconnecting due to network loss',
|
|
1498
|
+
);
|
|
1499
|
+
disconnect();
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1502
|
+
|
|
1503
|
+
self.connect = () => {
|
|
1504
|
+
log(TYPE_MANAGER, 'ConnectionManager::connect()');
|
|
1505
|
+
|
|
1506
|
+
// resolve connect instantly if the process has been already postponed
|
|
1507
|
+
if (connectDelay.active) {
|
|
1508
|
+
connectDelay.resolve();
|
|
1509
|
+
} else if (state === self.STATE_DISCONNECTED) {
|
|
1510
|
+
setStateToConnecting();
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
window.addEventListener('online', handleNetworkStatus);
|
|
1514
|
+
window.addEventListener('offline', handleNetworkStatus);
|
|
1515
|
+
window.addEventListener('visibilitychange', handleVisibilityChange);
|
|
1516
|
+
};
|
|
1517
|
+
|
|
1518
|
+
self.disconnect = () => {
|
|
1519
|
+
log(TYPE_MANAGER, 'ConnectionManager::disconnect()');
|
|
1520
|
+
|
|
1521
|
+
setStateToDisconnecting();
|
|
1522
|
+
|
|
1523
|
+
window.removeEventListener('online', handleNetworkStatus);
|
|
1524
|
+
window.removeEventListener('offline', handleNetworkStatus);
|
|
1525
|
+
window.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
1526
|
+
};
|
|
1527
|
+
|
|
1528
|
+
self.send = (sscp, success, failure) => {
|
|
1529
|
+
log(TYPE_MANAGER, 'ConnectionManager::send', sscp);
|
|
1530
|
+
success = success || (() => {});
|
|
1531
|
+
failure = failure || (() => {});
|
|
1532
|
+
transport.send(sscp, success, failure);
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1535
|
+
self.getConnectAttempt = () => attempt;
|
|
1536
|
+
|
|
1537
|
+
self.init = (cfg) => {
|
|
1538
|
+
log(TYPE_MANAGER, 'ConnectionManager::init()', cfg);
|
|
1539
|
+
config = cfg;
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1542
|
+
return self;
|
|
1543
|
+
})();
|
|
1544
|
+
|
|
1545
|
+
/* eslint-disable no-console */
|
|
1546
|
+
|
|
1547
|
+
class Demographics extends sdkUtil.Emitter {
|
|
1548
|
+
constructor(...args) {
|
|
1549
|
+
super(...args);
|
|
1550
|
+
|
|
1551
|
+
this.ON_ADD_COUNTER = 'add-counter';
|
|
1552
|
+
|
|
1553
|
+
this.trigger = this.emit;
|
|
1554
|
+
this.bind = this.on;
|
|
1555
|
+
this.unbind = this.off;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
addCounter(
|
|
1559
|
+
channel,
|
|
1560
|
+
eventId,
|
|
1561
|
+
segment,
|
|
1562
|
+
counter,
|
|
1563
|
+
round = null,
|
|
1564
|
+
min = null,
|
|
1565
|
+
max = null,
|
|
1566
|
+
) {
|
|
1567
|
+
log(
|
|
1568
|
+
TYPE_SERVICE,
|
|
1569
|
+
'Demographics::addCounter',
|
|
1570
|
+
channel,
|
|
1571
|
+
eventId,
|
|
1572
|
+
segment,
|
|
1573
|
+
counter,
|
|
1574
|
+
round,
|
|
1575
|
+
min,
|
|
1576
|
+
max,
|
|
1577
|
+
);
|
|
1578
|
+
|
|
1579
|
+
if (!channel) {
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
if (!eventId) {
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
if (
|
|
1588
|
+
!segment ||
|
|
1589
|
+
segment.constructor !== Array ||
|
|
1590
|
+
!segment.length ||
|
|
1591
|
+
segment.length % 2 !== 0
|
|
1592
|
+
) {
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
if (counter !== parseInt(counter, 10)) {
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
const keys = segment.filter((v, i) => (i + 1) % 2).join(':');
|
|
1601
|
+
const values = segment.filter((v, i) => i % 2).join(':');
|
|
1602
|
+
|
|
1603
|
+
this.trigger(this.ON_ADD_COUNTER, channel, [
|
|
1604
|
+
eventId,
|
|
1605
|
+
min,
|
|
1606
|
+
max,
|
|
1607
|
+
round,
|
|
1608
|
+
keys,
|
|
1609
|
+
values,
|
|
1610
|
+
counter,
|
|
1611
|
+
]);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
var Demographics$1 = new Demographics();
|
|
1616
|
+
|
|
1617
|
+
/* eslint-disable no-console */
|
|
1618
|
+
|
|
1619
|
+
const Enmasse = (() => {
|
|
1620
|
+
/*
|
|
1621
|
+
* Link to the scope
|
|
1622
|
+
*/
|
|
1623
|
+
|
|
1624
|
+
const self = new sdkUtil.Emitter();
|
|
1625
|
+
|
|
1626
|
+
self.trigger = self.emit;
|
|
1627
|
+
self.bind = self.on;
|
|
1628
|
+
self.unbind = self.off;
|
|
1629
|
+
|
|
1630
|
+
/*
|
|
1631
|
+
* Constants
|
|
1632
|
+
*/
|
|
1633
|
+
|
|
1634
|
+
self.VERSION = version;
|
|
1635
|
+
self.PROTOCOL_VERSION = '8';
|
|
1636
|
+
|
|
1637
|
+
self.SSCP_KLASS_AUTH = SSCP_KLASS_AUTH;
|
|
1638
|
+
self.SSCP_KLASS_AUTHR = SSCP_KLASS_AUTHR;
|
|
1639
|
+
self.SSCP_KLASS_AUTHOK = SSCP_KLASS_AUTHOK;
|
|
1640
|
+
self.SSCP_KLASS_PING = SSCP_KLASS_PING;
|
|
1641
|
+
self.SSCP_KLASS_SUB = SSCP_KLASS_SUB;
|
|
1642
|
+
self.SSCP_KLASS_UNSUB = SSCP_KLASS_UNSUB;
|
|
1643
|
+
self.SSCP_KLASS_EOC = SSCP_KLASS_EOC;
|
|
1644
|
+
self.SSCP_KLASS_LOGIN = SSCP_KLASS_LOGIN;
|
|
1645
|
+
self.SSCP_KLASS_LOGOUT = SSCP_KLASS_LOGOUT;
|
|
1646
|
+
self.SSCP_KLASS_COUNTER = SSCP_KLASS_COUNTER;
|
|
1647
|
+
|
|
1648
|
+
self.ON_STATE = 'on_state';
|
|
1649
|
+
self.ON_MESSAGE = 'on_message';
|
|
1650
|
+
self.ON_EOC = 'on_eoc';
|
|
1651
|
+
self.ON_READY = 'on_ready';
|
|
1652
|
+
self.ON_ERROR = 'on_error';
|
|
1653
|
+
|
|
1654
|
+
self.STATE_DISCONNECTED = 'disconnected';
|
|
1655
|
+
self.STATE_CONNECTED = 'connected';
|
|
1656
|
+
self.STATE_CONNECTING = 'connecting';
|
|
1657
|
+
|
|
1658
|
+
self.Demographics = Demographics$1;
|
|
1659
|
+
|
|
1660
|
+
// var CALLBACK_NAME = "__enmasse_callback";
|
|
1661
|
+
// var CONFIG_TIMEOUT = 5000;
|
|
1662
|
+
|
|
1663
|
+
const PARAM_SESSION_ID = 'enmasse_session_id';
|
|
1664
|
+
|
|
1665
|
+
/*
|
|
1666
|
+
* Enmasse properties
|
|
1667
|
+
*/
|
|
1668
|
+
|
|
1669
|
+
// Link to the config file.
|
|
1670
|
+
let configFile = null;
|
|
1671
|
+
|
|
1672
|
+
// list of arbitray data passed into handshake
|
|
1673
|
+
// message along with the protocol version
|
|
1674
|
+
let info = [];
|
|
1675
|
+
|
|
1676
|
+
// session id is generated by server and passed
|
|
1677
|
+
// on client on handshake
|
|
1678
|
+
let sessionId = null;
|
|
1679
|
+
|
|
1680
|
+
// out messages queue
|
|
1681
|
+
let queue = null;
|
|
1682
|
+
|
|
1683
|
+
// current state of the state machine
|
|
1684
|
+
let state = self.STATE_DISCONNECTED;
|
|
1685
|
+
|
|
1686
|
+
// system channel
|
|
1687
|
+
let sysChannel = null;
|
|
1688
|
+
|
|
1689
|
+
// force secure connection
|
|
1690
|
+
let forceSecure = false;
|
|
1691
|
+
|
|
1692
|
+
// sign in promise object
|
|
1693
|
+
let loginContext = {
|
|
1694
|
+
inProgress: false,
|
|
1695
|
+
success: () => {},
|
|
1696
|
+
failure: () => {},
|
|
1697
|
+
};
|
|
1698
|
+
|
|
1699
|
+
/*
|
|
1700
|
+
* Private methods
|
|
1701
|
+
*/
|
|
1702
|
+
|
|
1703
|
+
const storeSession = async (id) => {
|
|
1704
|
+
try {
|
|
1705
|
+
await sdkStorageKit.storageWrite(PARAM_SESSION_ID, id);
|
|
1706
|
+
} catch (err) {
|
|
1707
|
+
console.error(
|
|
1708
|
+
`Failed to persist session to shared storage: ${sdkUtil.getErrorMessage(err)}`,
|
|
1709
|
+
);
|
|
1710
|
+
}
|
|
1711
|
+
};
|
|
1712
|
+
|
|
1713
|
+
const restoreSession = async () => {
|
|
1714
|
+
let restoredId = null;
|
|
1715
|
+
|
|
1716
|
+
// Read session from shared storage
|
|
1717
|
+
try {
|
|
1718
|
+
restoredId = await sdkStorageKit.storageRead(PARAM_SESSION_ID);
|
|
1719
|
+
} catch (err) {
|
|
1720
|
+
console.error(
|
|
1721
|
+
`Failed to read session from shared storage: ${sdkUtil.getErrorMessage(err)}`,
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
if (restoredId !== null) {
|
|
1726
|
+
return restoredId;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
/**
|
|
1730
|
+
* Further down is a special case when we try to restore session id from the
|
|
1731
|
+
* local storage and save it to the shared storage. This could happen in
|
|
1732
|
+
* previous versions of the SDK when we didn't have a shared storage.
|
|
1733
|
+
*/
|
|
1734
|
+
|
|
1735
|
+
if (sdkLauncherKit.getParentApplication() === null) {
|
|
1736
|
+
return null;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
try {
|
|
1740
|
+
restoredId = sdkUtil.getItem(PARAM_SESSION_ID);
|
|
1741
|
+
} catch (err) {
|
|
1742
|
+
console.error(
|
|
1743
|
+
`Failed to read local session during migration: ${sdkUtil.getErrorMessage(
|
|
1744
|
+
err,
|
|
1745
|
+
)}`,
|
|
1746
|
+
);
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
if (restoredId === null) {
|
|
1750
|
+
return null;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
try {
|
|
1754
|
+
await sdkStorageKit.storageWrite(PARAM_SESSION_ID, restoredId);
|
|
1755
|
+
} catch (err) {
|
|
1756
|
+
console.error(
|
|
1757
|
+
`Failed to persist session to shared storage during migration: ${sdkUtil.getErrorMessage(
|
|
1758
|
+
err,
|
|
1759
|
+
)}`,
|
|
1760
|
+
);
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
return restoredId;
|
|
1764
|
+
};
|
|
1765
|
+
|
|
1766
|
+
const resetSession = async () => {
|
|
1767
|
+
sessionId = null;
|
|
1768
|
+
|
|
1769
|
+
try {
|
|
1770
|
+
await sdkStorageKit.storageRemove(PARAM_SESSION_ID);
|
|
1771
|
+
} catch (err) {
|
|
1772
|
+
console.error(
|
|
1773
|
+
`Failed to remove session from shared storage: ${sdkUtil.getErrorMessage(err)}`,
|
|
1774
|
+
);
|
|
1775
|
+
}
|
|
1776
|
+
};
|
|
1777
|
+
|
|
1778
|
+
const validateSession = (id) =>
|
|
1779
|
+
// eslint-disable-next-line
|
|
1780
|
+
/^[a-f\d]{8}\-[a-f\d]{4}\-[a-f\d]{4}-[a-f\d]{4}\-[a-f\d]{12}$/i.test(id);
|
|
1781
|
+
|
|
1782
|
+
const finaliseLogin = (callback) => {
|
|
1783
|
+
if (loginContext.inProgress === false) {
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
loginContext = {
|
|
1788
|
+
inProgress: false,
|
|
1789
|
+
success: () => {},
|
|
1790
|
+
failure: () => {},
|
|
1791
|
+
};
|
|
1792
|
+
|
|
1793
|
+
callback();
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1796
|
+
const resolveLogin = () => {
|
|
1797
|
+
finaliseLogin(loginContext.success);
|
|
1798
|
+
};
|
|
1799
|
+
|
|
1800
|
+
const rejectLogin = () => {
|
|
1801
|
+
finaliseLogin(loginContext.failure);
|
|
1802
|
+
};
|
|
1803
|
+
|
|
1804
|
+
const setStateToDisconnected = () => {
|
|
1805
|
+
log(TYPE_PROTOCOL, 'Enmasse::setStateToDisconnected()');
|
|
1806
|
+
|
|
1807
|
+
state = self.STATE_DISCONNECTED;
|
|
1808
|
+
sysChannel = null;
|
|
1809
|
+
|
|
1810
|
+
rejectLogin();
|
|
1811
|
+
|
|
1812
|
+
self.trigger(self.ON_STATE, state);
|
|
1813
|
+
};
|
|
1814
|
+
|
|
1815
|
+
const setStateToConnected = () => {
|
|
1816
|
+
log(TYPE_PROTOCOL, 'Enmasse::setStateToConnected()');
|
|
1817
|
+
|
|
1818
|
+
const time = now();
|
|
1819
|
+
state = self.STATE_CONNECTED;
|
|
1820
|
+
self.trigger(self.ON_STATE, state, time);
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1823
|
+
const setStateToConnecting = (attempt, delay) => {
|
|
1824
|
+
log(TYPE_PROTOCOL, 'Enmasse::setStateToConnecting()');
|
|
1825
|
+
|
|
1826
|
+
state = self.STATE_CONNECTING;
|
|
1827
|
+
rejectLogin();
|
|
1828
|
+
|
|
1829
|
+
self.trigger(self.ON_STATE, state, attempt, delay);
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1832
|
+
const parseSSCP = (sscp) => {
|
|
1833
|
+
const data = {
|
|
1834
|
+
channel: 0,
|
|
1835
|
+
klass: '',
|
|
1836
|
+
sent_at: 0,
|
|
1837
|
+
body: [],
|
|
1838
|
+
};
|
|
1839
|
+
|
|
1840
|
+
const separator1 = sscp.indexOf('/');
|
|
1841
|
+
|
|
1842
|
+
if (separator1 !== -1) {
|
|
1843
|
+
const separator2 = sscp.indexOf('/', separator1 + 1);
|
|
1844
|
+
|
|
1845
|
+
if (separator2 !== -1) {
|
|
1846
|
+
data.channel = sscp.substr(0, separator1);
|
|
1847
|
+
data.klass = sscp.substr(separator1 + 1, separator2 - separator1 - 1);
|
|
1848
|
+
|
|
1849
|
+
const separator3 = sscp.indexOf('/', separator2 + 1);
|
|
1850
|
+
|
|
1851
|
+
if (separator3 !== -1) {
|
|
1852
|
+
data.sent_at = parseInt(
|
|
1853
|
+
sscp.substr(separator2 + 1, separator3 - separator2 - 1),
|
|
1854
|
+
10,
|
|
1855
|
+
);
|
|
1856
|
+
|
|
1857
|
+
const body = sscp.substr(separator3 + 1);
|
|
1858
|
+
|
|
1859
|
+
if (body !== '') {
|
|
1860
|
+
const values = body.split('|');
|
|
1861
|
+
|
|
1862
|
+
for (let i = 0, l = values.length; i < l; i += 1) {
|
|
1863
|
+
data.body[i] = decodeURIComponent(values[i]);
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
return data;
|
|
1871
|
+
};
|
|
1872
|
+
|
|
1873
|
+
const stringifySSCP = (message) =>
|
|
1874
|
+
[
|
|
1875
|
+
message.channel,
|
|
1876
|
+
message.klass,
|
|
1877
|
+
Math.floor(new Date() / 1000),
|
|
1878
|
+
message.body.join('|'),
|
|
1879
|
+
].join('/');
|
|
1880
|
+
|
|
1881
|
+
const runner = (message) => {
|
|
1882
|
+
const success = () => {
|
|
1883
|
+
queue.success();
|
|
1884
|
+
};
|
|
1885
|
+
|
|
1886
|
+
const failure = () => {
|
|
1887
|
+
queue.failure();
|
|
1888
|
+
};
|
|
1889
|
+
|
|
1890
|
+
ConnectionManager.send(stringifySSCP(message), success, failure);
|
|
1891
|
+
};
|
|
1892
|
+
|
|
1893
|
+
const handleTransportManagerReady = () => {
|
|
1894
|
+
log(TYPE_PROTOCOL, 'Enmasse::handleTransportManagerReady');
|
|
1895
|
+
self.trigger(self.ON_READY);
|
|
1896
|
+
};
|
|
1897
|
+
|
|
1898
|
+
const handleConnectionManagerState = (...args) => {
|
|
1899
|
+
log(
|
|
1900
|
+
TYPE_PROTOCOL,
|
|
1901
|
+
'Enmasse::handleConnectionManagerState',
|
|
1902
|
+
args,
|
|
1903
|
+
);
|
|
1904
|
+
|
|
1905
|
+
switch (args[0]) {
|
|
1906
|
+
// case ConnectionManager.STATE_DISCONNECTING:
|
|
1907
|
+
// break;
|
|
1908
|
+
case ConnectionManager.STATE_DISCONNECTED:
|
|
1909
|
+
setStateToDisconnected();
|
|
1910
|
+
break;
|
|
1911
|
+
case ConnectionManager.STATE_CONNECTING:
|
|
1912
|
+
setStateToConnecting(args[1], args[2]);
|
|
1913
|
+
break;
|
|
1914
|
+
case ConnectionManager.STATE_CONNECTED:
|
|
1915
|
+
break;
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
|
|
1919
|
+
const handleConnectionManagerMessage = async (message) => {
|
|
1920
|
+
log(
|
|
1921
|
+
TYPE_PROTOCOL,
|
|
1922
|
+
'Enmasse::handleConnectionManagerMessage',
|
|
1923
|
+
message,
|
|
1924
|
+
);
|
|
1925
|
+
|
|
1926
|
+
const data = parseSSCP(message);
|
|
1927
|
+
|
|
1928
|
+
switch (data.klass) {
|
|
1929
|
+
case SSCP_KLASS_AUTH: {
|
|
1930
|
+
const time = data.sent_at;
|
|
1931
|
+
|
|
1932
|
+
const clientInfo = [
|
|
1933
|
+
`enmassejs-${self.VERSION}`,
|
|
1934
|
+
navigator.userAgent,
|
|
1935
|
+
].concat(info);
|
|
1936
|
+
|
|
1937
|
+
// store system channel
|
|
1938
|
+
sysChannel = data.channel;
|
|
1939
|
+
|
|
1940
|
+
// url encode each client info item
|
|
1941
|
+
clientInfo.forEach((item, idx) => {
|
|
1942
|
+
clientInfo[idx] = encodeURIComponent(item);
|
|
1943
|
+
});
|
|
1944
|
+
|
|
1945
|
+
if (sessionId === null) {
|
|
1946
|
+
[sessionId] = data.body;
|
|
1947
|
+
await storeSession(sessionId);
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
setTime(time);
|
|
1951
|
+
|
|
1952
|
+
queue.stash();
|
|
1953
|
+
|
|
1954
|
+
queue.push(
|
|
1955
|
+
{
|
|
1956
|
+
channel: sysChannel,
|
|
1957
|
+
klass: SSCP_KLASS_AUTHR,
|
|
1958
|
+
body: [sessionId, self.PROTOCOL_VERSION, clientInfo.join(',')],
|
|
1959
|
+
},
|
|
1960
|
+
true,
|
|
1961
|
+
);
|
|
1962
|
+
|
|
1963
|
+
queue.run();
|
|
1964
|
+
|
|
1965
|
+
break;
|
|
1966
|
+
}
|
|
1967
|
+
case SSCP_KLASS_AUTHOK: {
|
|
1968
|
+
// We have to resubscribe to the previously
|
|
1969
|
+
// subscribed channels after the reconnect.
|
|
1970
|
+
const subscriptions = queue.getSubscriptions();
|
|
1971
|
+
|
|
1972
|
+
subscriptions.forEach((channel) => {
|
|
1973
|
+
queue.push(
|
|
1974
|
+
{
|
|
1975
|
+
channel,
|
|
1976
|
+
klass: SSCP_KLASS_SUB,
|
|
1977
|
+
body: [],
|
|
1978
|
+
},
|
|
1979
|
+
true,
|
|
1980
|
+
);
|
|
1981
|
+
});
|
|
1982
|
+
|
|
1983
|
+
queue.unstash();
|
|
1984
|
+
queue.run();
|
|
1985
|
+
|
|
1986
|
+
setStateToConnected();
|
|
1987
|
+
break;
|
|
1988
|
+
}
|
|
1989
|
+
case SSCP_KLASS_LOGIN_OK:
|
|
1990
|
+
resolveLogin();
|
|
1991
|
+
break;
|
|
1992
|
+
case SSCP_KLASS_LOGIN_FAIL:
|
|
1993
|
+
rejectLogin();
|
|
1994
|
+
break;
|
|
1995
|
+
case SSCP_KLASS_PING:
|
|
1996
|
+
// ignoring ping message handling
|
|
1997
|
+
break;
|
|
1998
|
+
case SSCP_KLASS_EOC:
|
|
1999
|
+
self.trigger(self.ON_EOC, data.channel);
|
|
2000
|
+
break;
|
|
2001
|
+
default:
|
|
2002
|
+
self.trigger(self.ON_MESSAGE, data);
|
|
2003
|
+
break;
|
|
2004
|
+
}
|
|
2005
|
+
};
|
|
2006
|
+
|
|
2007
|
+
const handleDemographicsCounter = (channel, data) => {
|
|
2008
|
+
self.send(channel, 'avgcounter', data);
|
|
2009
|
+
};
|
|
2010
|
+
|
|
2011
|
+
/**
|
|
2012
|
+
* @internal
|
|
2013
|
+
*/
|
|
2014
|
+
self.PARAM_SESSION_ID = PARAM_SESSION_ID;
|
|
2015
|
+
|
|
2016
|
+
/**
|
|
2017
|
+
* @internal
|
|
2018
|
+
*/
|
|
2019
|
+
self.resetSession = resetSession;
|
|
2020
|
+
|
|
2021
|
+
/*
|
|
2022
|
+
* Public methods
|
|
2023
|
+
*/
|
|
2024
|
+
|
|
2025
|
+
self.connect = () => {
|
|
2026
|
+
log(TYPE_PROTOCOL, 'Enmasse::connect');
|
|
2027
|
+
|
|
2028
|
+
ConnectionManager.connect();
|
|
2029
|
+
};
|
|
2030
|
+
|
|
2031
|
+
self.disconnect = () => {
|
|
2032
|
+
log(TYPE_PROTOCOL, 'Enmasse:disconnect');
|
|
2033
|
+
|
|
2034
|
+
ConnectionManager.disconnect();
|
|
2035
|
+
};
|
|
2036
|
+
|
|
2037
|
+
self.send = (channel, klass, body) => {
|
|
2038
|
+
log(TYPE_PROTOCOL, 'Enmasse::send', channel, klass, body);
|
|
2039
|
+
|
|
2040
|
+
body = body || [];
|
|
2041
|
+
|
|
2042
|
+
queue.push({
|
|
2043
|
+
channel,
|
|
2044
|
+
klass,
|
|
2045
|
+
body,
|
|
2046
|
+
});
|
|
2047
|
+
|
|
2048
|
+
if (state === self.STATE_CONNECTED) {
|
|
2049
|
+
queue.run();
|
|
2050
|
+
}
|
|
2051
|
+
};
|
|
2052
|
+
|
|
2053
|
+
self.getSessionId = () => sessionId;
|
|
2054
|
+
|
|
2055
|
+
self.getState = () => state;
|
|
2056
|
+
|
|
2057
|
+
self.subscribe = (channel) => {
|
|
2058
|
+
self.send(channel, SSCP_KLASS_SUB);
|
|
2059
|
+
};
|
|
2060
|
+
|
|
2061
|
+
self.unsubscribe = (channel) => {
|
|
2062
|
+
self.send(channel, SSCP_KLASS_UNSUB);
|
|
2063
|
+
};
|
|
2064
|
+
|
|
2065
|
+
self.login = (
|
|
2066
|
+
userId,
|
|
2067
|
+
timestamp,
|
|
2068
|
+
signature,
|
|
2069
|
+
success = () => {},
|
|
2070
|
+
failure = () => {},
|
|
2071
|
+
) => {
|
|
2072
|
+
if (sysChannel === null) {
|
|
2073
|
+
return;
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
if (loginContext.inProgress) {
|
|
2077
|
+
console.warn('Login is already in progress');
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
loginContext = { inProgress: true, success, failure };
|
|
2082
|
+
|
|
2083
|
+
self.send(sysChannel, SSCP_KLASS_LOGIN, [userId, timestamp, signature]);
|
|
2084
|
+
};
|
|
2085
|
+
|
|
2086
|
+
self.logout = () => {
|
|
2087
|
+
if (sysChannel === null) {
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
if (loginContext.inProgress) {
|
|
2092
|
+
rejectLogin();
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
self.send(sysChannel, SSCP_KLASS_LOGOUT);
|
|
2096
|
+
};
|
|
2097
|
+
|
|
2098
|
+
self.init = async function init(config = () => {}) {
|
|
2099
|
+
// config file is passed either as GET parameter or via constructor
|
|
2100
|
+
configFile = !ENMASSE_CONFIG ? config.config || null : ENMASSE_CONFIG;
|
|
2101
|
+
info = config.info || [];
|
|
2102
|
+
sessionId = await restoreSession();
|
|
2103
|
+
|
|
2104
|
+
if (typeof config.forceSecure === 'boolean') {
|
|
2105
|
+
forceSecure = config.forceSecure;
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
if (configFile === null) {
|
|
2109
|
+
// eslint-disable-next-line
|
|
2110
|
+
throw 'EnMasse config file is not set';
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
// If session id has invalid format
|
|
2114
|
+
if (sessionId !== null && !validateSession(sessionId)) {
|
|
2115
|
+
await resetSession();
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
queue = new Queue({
|
|
2119
|
+
runner,
|
|
2120
|
+
});
|
|
2121
|
+
|
|
2122
|
+
TransportManager$1.bind(
|
|
2123
|
+
TransportManager$1.ON_READY,
|
|
2124
|
+
handleTransportManagerReady,
|
|
2125
|
+
);
|
|
2126
|
+
ConnectionManager.bind(
|
|
2127
|
+
ConnectionManager.ON_STATE,
|
|
2128
|
+
handleConnectionManagerState,
|
|
2129
|
+
);
|
|
2130
|
+
ConnectionManager.bind(
|
|
2131
|
+
ConnectionManager.ON_MESSAGE,
|
|
2132
|
+
handleConnectionManagerMessage,
|
|
2133
|
+
);
|
|
2134
|
+
Demographics$1.bind(Demographics$1.ON_ADD_COUNTER, handleDemographicsCounter);
|
|
2135
|
+
|
|
2136
|
+
try {
|
|
2137
|
+
const response = await fetch(configFile);
|
|
2138
|
+
|
|
2139
|
+
const { status, statusText: text } = response;
|
|
2140
|
+
|
|
2141
|
+
let data;
|
|
2142
|
+
|
|
2143
|
+
try {
|
|
2144
|
+
data = await response.json();
|
|
2145
|
+
} catch (jsonErr) {
|
|
2146
|
+
self.trigger(self.ON_ERROR, `Invalid JSON from config ${configFile}`);
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
|
|
2150
|
+
const isSuccess =
|
|
2151
|
+
(status >= 200 && status <= 300) ||
|
|
2152
|
+
// If you conclude with an XMLHttpRequest receiving status=0 and
|
|
2153
|
+
// statusText=null, this means the request was not allowed to be
|
|
2154
|
+
// performed.
|
|
2155
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#xmlhttprequests_being_stopped
|
|
2156
|
+
(status === 0 && !!text) ||
|
|
2157
|
+
status === '';
|
|
2158
|
+
|
|
2159
|
+
data.forceSecure = forceSecure;
|
|
2160
|
+
|
|
2161
|
+
if (data.background_timeout === undefined) {
|
|
2162
|
+
data.background_timeout = 0;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
if (isSuccess) {
|
|
2166
|
+
ConnectionManager.init(data);
|
|
2167
|
+
TransportManager$1.init(data);
|
|
2168
|
+
} else {
|
|
2169
|
+
self.trigger(self.ON_ERROR, `Failed to load config ${configFile}`);
|
|
2170
|
+
}
|
|
2171
|
+
} catch (err) {
|
|
2172
|
+
self.trigger(self.ON_ERROR, `Error loading config: ${err.message}`);
|
|
2173
|
+
}
|
|
2174
|
+
};
|
|
2175
|
+
|
|
2176
|
+
return self;
|
|
2177
|
+
})();
|
|
2178
|
+
|
|
2179
|
+
module.exports = Enmasse;
|
|
2180
|
+
//# sourceMappingURL=index.cjs.map
|