comprodls-sdk 2.84.0 → 2.86.0-alpha
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.
|
@@ -26,9 +26,7 @@
|
|
|
26
26
|
var ERROR_TYPES = {
|
|
27
27
|
"API_ERROR": "API_ERROR",
|
|
28
28
|
"SDK_ERROR": "SDK_ERROR",
|
|
29
|
-
"CHANNEL_SUBSCRIPTION": "CHANNEL_SUBSCRIPTION"
|
|
30
|
-
"UNEXPECTED_ERROR": "UNEXPECTED_ERROR",
|
|
31
|
-
"POLLING_INITIATION": "POLLING_INITIATION"
|
|
29
|
+
"CHANNEL_SUBSCRIPTION": "CHANNEL_SUBSCRIPTION"
|
|
32
30
|
};
|
|
33
31
|
|
|
34
32
|
var ERROR_CATEGORY = {
|
|
@@ -724,14 +724,17 @@ function getClassesOfAGradeformat(options) {
|
|
|
724
724
|
|
|
725
725
|
/*
|
|
726
726
|
options = {
|
|
727
|
-
assignedpathid: "string", //Mandatory
|
|
727
|
+
assignedpathid: "string", // Mandatory
|
|
728
728
|
classid: "string", // Mandatory
|
|
729
|
-
body :
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
729
|
+
body : {
|
|
730
|
+
"users":[ // min:1 , max: 50
|
|
731
|
+
{
|
|
732
|
+
extUserId: "string", // Mandatory
|
|
733
|
+
}
|
|
734
|
+
....
|
|
735
|
+
],
|
|
736
|
+
"context": {} // Optional
|
|
737
|
+
}
|
|
735
738
|
}
|
|
736
739
|
*/
|
|
737
740
|
function createUserAssignedPathEnrollments(options) {
|
|
@@ -79,8 +79,12 @@ function _connect(pubnubCW, options) {
|
|
|
79
79
|
'pubnub': {
|
|
80
80
|
'publishKey': options.publishKey,
|
|
81
81
|
'subscribeKey': options.subscribeKey,
|
|
82
|
-
'ssl': true
|
|
83
|
-
|
|
82
|
+
'ssl': true,
|
|
83
|
+
'suppressLeaveEvents': true
|
|
84
|
+
},
|
|
85
|
+
'pollingEndpoint': options.pollingEndpoint,
|
|
86
|
+
'pollingIterations': options.pollingIterations || 10, // Default polling iterations is 10
|
|
87
|
+
'pollingInterval': options.pollingInterval, // Default polling interval is exponential backoff
|
|
84
88
|
});
|
|
85
89
|
}
|
|
86
90
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var pubNub = require("pubnub");
|
|
2
|
+
var request = require('superagent');
|
|
2
3
|
var EventEmitter = require("events").EventEmitter;
|
|
3
4
|
var helpers = require('../../helpers');
|
|
4
5
|
|
|
@@ -21,6 +22,13 @@ module.exports = function () {
|
|
|
21
22
|
var _globalSubscription = [];
|
|
22
23
|
var _globalSubscriptionStatus = {};
|
|
23
24
|
var bStatusSubscribed = false;
|
|
25
|
+
/** ID of the setTimeout - used for Polling events when PubNub fails */
|
|
26
|
+
var _setTimeoutIDForPolling;
|
|
27
|
+
/** Timestamp from when the events need to be fetched */
|
|
28
|
+
var _startTimestampForPolling;
|
|
29
|
+
/** Counter for polling */
|
|
30
|
+
var _pollingCounter;
|
|
31
|
+
var bPollingInitiated = false;
|
|
24
32
|
|
|
25
33
|
/** ###### END OF MODULE GLOBALS */
|
|
26
34
|
|
|
@@ -36,6 +44,9 @@ module.exports = function () {
|
|
|
36
44
|
//Returning the adaptor (Plain Javascript object)
|
|
37
45
|
return {
|
|
38
46
|
"on": function (channelObj, handler) {
|
|
47
|
+
// If PubNub fails, we will fetch the events from this timestamp
|
|
48
|
+
_startTimestampForPolling = Date.now();
|
|
49
|
+
|
|
39
50
|
var pubNubChannel;
|
|
40
51
|
var channelContext = [];
|
|
41
52
|
|
|
@@ -64,6 +75,9 @@ module.exports = function () {
|
|
|
64
75
|
_eventEmitter.on(channelObj.channel, handler);
|
|
65
76
|
bStatusSubscribed = true;
|
|
66
77
|
}
|
|
78
|
+
|
|
79
|
+
// Clean up the old events
|
|
80
|
+
_checkOldBubbledEvents();
|
|
67
81
|
},
|
|
68
82
|
"getMySubscriptionStatus": __getMySubscriptionStatus
|
|
69
83
|
};
|
|
@@ -77,6 +91,10 @@ module.exports = function () {
|
|
|
77
91
|
|
|
78
92
|
var _translatePubnubStatus = function(status, options) {
|
|
79
93
|
var channels = [], error, successObj;
|
|
94
|
+
|
|
95
|
+
// If polling has been initiated, ignore all punnub status
|
|
96
|
+
if (bPollingInitiated) return;
|
|
97
|
+
|
|
80
98
|
switch (status.category) {
|
|
81
99
|
case "PNConnectedCategory":
|
|
82
100
|
if(status.operation === "PNSubscribeOperation") {
|
|
@@ -138,11 +156,10 @@ module.exports = function () {
|
|
|
138
156
|
break;
|
|
139
157
|
case "PNNetworkIssuesCategory":
|
|
140
158
|
if(status.operation === 'PNSubscribeOperation') {
|
|
141
|
-
if(!options.accountId) {
|
|
159
|
+
if(!options.accountId || !_userOptions.pollingEndpoint) {
|
|
142
160
|
error = {
|
|
143
|
-
message: "Missing mandatory parameters to initiate polling operation - accountId",
|
|
144
|
-
status: status.statusCode
|
|
145
|
-
type: helpers.errors.ERROR_TYPES.POLLING_INITIATION,
|
|
161
|
+
message: "Polling initiation error: Missing mandatory parameters to initiate polling operation - [accountId, pollingEndpoint]",
|
|
162
|
+
status: status.statusCode
|
|
146
163
|
};
|
|
147
164
|
error = new PUSHXError(helpers.errors.ERROR_CATEGORY.PUSHX, error);
|
|
148
165
|
_eventEmitter.emit('pushx_status', error);
|
|
@@ -156,6 +173,9 @@ module.exports = function () {
|
|
|
156
173
|
* The wrapper supports multiple channels, but the APP currently uses a single channel only.
|
|
157
174
|
* Polling will also limited to a single channel.
|
|
158
175
|
*/
|
|
176
|
+
_pollingCounter = 0;
|
|
177
|
+
_pollForEvents();
|
|
178
|
+
bPollingInitiated = true;
|
|
159
179
|
}
|
|
160
180
|
}
|
|
161
181
|
else {
|
|
@@ -168,9 +188,8 @@ module.exports = function () {
|
|
|
168
188
|
default:
|
|
169
189
|
// Emit error for other status-category received from pubnub
|
|
170
190
|
error = {
|
|
171
|
-
message: "PushX Error",
|
|
191
|
+
message: "PushX Error: unexpected error",
|
|
172
192
|
status: status.statusCode,
|
|
173
|
-
type: helpers.errors.ERROR_TYPES.UNEXPECTED_ERROR,
|
|
174
193
|
pushXError: status
|
|
175
194
|
};
|
|
176
195
|
error = new PUSHXError(helpers.errors.ERROR_CATEGORY.PUSHX, error);
|
|
@@ -207,6 +226,7 @@ module.exports = function () {
|
|
|
207
226
|
* @returns PROMISE.
|
|
208
227
|
*/
|
|
209
228
|
var __setup = function (userOptions) {
|
|
229
|
+
|
|
210
230
|
var pubnubConfig = userOptions.pubnub;
|
|
211
231
|
pubnubConfig.uuid = userOptions.userid;
|
|
212
232
|
var accountId = userOptions.accountid;
|
|
@@ -245,8 +265,169 @@ module.exports = function () {
|
|
|
245
265
|
_globalSubscription = [];
|
|
246
266
|
bStatusSubscribed = false;
|
|
247
267
|
_globalSubscriptionStatus = {};
|
|
268
|
+
bPollingInitiated = false;
|
|
248
269
|
}
|
|
249
270
|
_pubnubClient = undefined;
|
|
271
|
+
|
|
272
|
+
// Clear the Polling
|
|
273
|
+
if (_setTimeoutIDForPolling) {
|
|
274
|
+
clearTimeout(_setTimeoutIDForPolling);
|
|
275
|
+
// Setting the start time to now to clear the old events
|
|
276
|
+
_startTimestampForPolling = Date.now();
|
|
277
|
+
_checkOldBubbledEvents();
|
|
278
|
+
_setTimeoutIDForPolling = undefined;
|
|
279
|
+
_pollingCounter = undefined;
|
|
280
|
+
_startTimestampForPolling = undefined;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Polling function
|
|
286
|
+
*/
|
|
287
|
+
var _pollForEvents = function () {
|
|
288
|
+
// Setup request params
|
|
289
|
+
var params = {
|
|
290
|
+
accountid: _userOptions.accountid,
|
|
291
|
+
channelname: _globalSubscription[0],
|
|
292
|
+
starttime: _startTimestampForPolling,
|
|
293
|
+
endtime: Date.now()
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// Safe check to avoid poll for events if the channel name or start time is not set
|
|
297
|
+
// This handles an edge condition where the clearTimeout doesn't work as expected
|
|
298
|
+
if (!params.channelname || !params.starttime) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
var requestAPI = request.get(_userOptions.pollingEndpoint).query(params);
|
|
303
|
+
|
|
304
|
+
requestAPI
|
|
305
|
+
.end(function(error, response) {
|
|
306
|
+
|
|
307
|
+
if (!error) {
|
|
308
|
+
// Bubble the connected status
|
|
309
|
+
if (_pollingCounter === 0) {
|
|
310
|
+
// Set the status of the channel to subscribed
|
|
311
|
+
if(_globalSubscriptionStatus[_globalSubscription[0]]) {
|
|
312
|
+
_globalSubscriptionStatus[_globalSubscription[0]].status = 'subscribed';
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
var successObj = {
|
|
316
|
+
category: 'PUSHX',
|
|
317
|
+
type: 'CHANNEL_SUBSCRIPTION',
|
|
318
|
+
status: 'SUCCESS',
|
|
319
|
+
message: 'Success: Subscribed successfully.',
|
|
320
|
+
httpcode: 200,
|
|
321
|
+
data: {
|
|
322
|
+
payload: {
|
|
323
|
+
channels: _globalSubscription
|
|
324
|
+
},
|
|
325
|
+
message: 'Success: Subscribed successfully.'
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
_eventEmitter.emit('pushx_status', successObj);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Bubble the received events
|
|
332
|
+
_bubblePolledEvents(response.body);
|
|
333
|
+
|
|
334
|
+
// Increase the counter
|
|
335
|
+
_pollingCounter++;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Polling will be done only for specific number of times
|
|
339
|
+
if (_pollingCounter > _userOptions.pollingIterations) {
|
|
340
|
+
var error = {
|
|
341
|
+
message: "Polling error: Polling limit exceeded",
|
|
342
|
+
status: 429
|
|
343
|
+
};
|
|
344
|
+
error = new PUSHXError(helpers.errors.ERROR_CATEGORY.PUSHX, error);
|
|
345
|
+
_eventEmitter.emit('pushx_status', error);
|
|
346
|
+
} else {
|
|
347
|
+
var timeoutDelay;
|
|
348
|
+
|
|
349
|
+
// If the polling interval is provided, use that
|
|
350
|
+
if (_userOptions.pollingInterval) {
|
|
351
|
+
timeoutDelay = _userOptions.pollingInterval * 60 * 1000;
|
|
352
|
+
} else {
|
|
353
|
+
// Else, use exponential backoff
|
|
354
|
+
timeoutDelay = parseInt(Math.pow(1.3, _pollingCounter) * 10 * 1000, 10);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Set timeout for next poll
|
|
358
|
+
if (timeoutDelay) {
|
|
359
|
+
_setTimeoutIDForPolling = setTimeout(_pollForEvents, timeoutDelay);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Bubble the polled events to the FE APP
|
|
367
|
+
* @param {*} events - Events recieved from the polling endpoint
|
|
368
|
+
*/
|
|
369
|
+
var _bubblePolledEvents = function (events) {
|
|
370
|
+
// Load the old events from the session storage
|
|
371
|
+
var oldEventData = _checkOldBubbledEvents();
|
|
372
|
+
|
|
373
|
+
var oldEvents = oldEventData.events;
|
|
374
|
+
var sessionStorageKey = oldEventData.key;
|
|
375
|
+
|
|
376
|
+
for (var i = 0; i < events.entities.length; i++) {
|
|
377
|
+
var event = events.entities[i];
|
|
378
|
+
var eventId = event.pk + '_' + event.sk;
|
|
379
|
+
|
|
380
|
+
// Check if the event is already emitted
|
|
381
|
+
if (!oldEvents[eventId]) {
|
|
382
|
+
oldEvents[eventId] = event.context.start_time;
|
|
383
|
+
|
|
384
|
+
// Emit the event
|
|
385
|
+
_eventEmitter.emit(_globalSubscription[0], event);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Save the bubbled events to session storage
|
|
390
|
+
sessionStorage.setItem(sessionStorageKey, JSON.stringify(oldEvents));
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Check the old bubbled events and remove the events that are older than the start timestamp
|
|
395
|
+
* @returns {object} - Object containing the key and the events
|
|
396
|
+
*/
|
|
397
|
+
var _checkOldBubbledEvents = function () {
|
|
398
|
+
var sessionStorageKey = 'comprodls.old_pushx_events.' + _userOptions.userid + '.' + _globalSubscription[0];
|
|
399
|
+
var oldEvents = sessionStorage.getItem(sessionStorageKey);
|
|
400
|
+
|
|
401
|
+
if (oldEvents) {
|
|
402
|
+
try {
|
|
403
|
+
oldEvents = JSON.parse(oldEvents);
|
|
404
|
+
} catch (e) {
|
|
405
|
+
oldEvents = {};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
var oldEventIds = Object.keys(oldEvents);
|
|
409
|
+
|
|
410
|
+
// Remove the events that are older than the start timestamp
|
|
411
|
+
for (var i = 0; i < oldEventIds.length; i++) {
|
|
412
|
+
var oldEventId = oldEventIds[i];
|
|
413
|
+
|
|
414
|
+
if (oldEvents[oldEventId] < _startTimestampForPolling) {
|
|
415
|
+
delete oldEvents[oldEventId];
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// If the number of events has changed, save the events
|
|
420
|
+
if (oldEventIds.length !== Object.keys(oldEvents).length) {
|
|
421
|
+
sessionStorage.setItem(sessionStorageKey, JSON.stringify(oldEvents));
|
|
422
|
+
}
|
|
423
|
+
} else {
|
|
424
|
+
oldEvents = {};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
key: sessionStorageKey,
|
|
429
|
+
events: oldEvents
|
|
430
|
+
};
|
|
250
431
|
};
|
|
251
432
|
|
|
252
433
|
return { // Return public methods for the wrapper
|
package/package.json
CHANGED