comprodls-sdk 2.90.3-development → 2.91.0-thor
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -137
- package/dist/comprodls-sdk.js +2917 -6291
- package/dist/comprodls-sdk.min.js +1 -1
- package/lib/comprodls.js +39 -57
- package/lib/config/index.js +172 -198
- package/lib/helpers/index.js +3 -2
- package/lib/helpers/lib/api/converter.js +1 -2
- package/lib/helpers/lib/api/index.js +19 -94
- package/lib/helpers/lib/errors.js +75 -80
- package/lib/helpers/lib/requestLayer.js +154 -0
- package/lib/helpers/lib/validator.js +65 -52
- package/lib/open_access/index.js +48 -53
- package/lib/services/analytics/index.js +286 -1014
- package/lib/services/attempts/index.js +38 -88
- package/lib/services/auth/index.js +324 -806
- package/lib/services/authextn/index.js +85 -247
- package/lib/services/datasyncmanager/index.js +10 -45
- package/lib/services/drive/index.js +20 -83
- package/lib/services/integrations/index.js +51 -126
- package/lib/services/invitations/index.js +20 -61
- package/lib/services/product/index.js +82 -85
- package/lib/services/pub/index.js +167 -235
- package/lib/services/pushX/index.js +195 -142
- package/lib/services/pushX/pubnubClientWrapper.js +399 -172
- package/lib/services/rules/index.js +14 -67
- package/lib/services/spaces/index.js +106 -289
- package/lib/services/spacesextn/index.js +44 -20
- package/lib/services/superuser/index.js +21 -36
- package/lib/services/taxonomy/index.js +27 -57
- package/lib/services/workflows/index.js +38 -97
- package/lib/services/xapi/index.js +7 -168
- package/lib/token/index.js +73 -67
- package/lib/token/validations.js +45 -48
- package/package.json +2 -3
- package/lib/helpers/lib/api/validations.js +0 -73
- package/lib/helpers/lib/utils.js +0 -24
- package/lib/services/activity/activity.js +0 -209
- package/lib/services/activity/attempt.js +0 -431
- package/lib/services/activity/index.js +0 -28
- package/lib/services/auth/classProduct.js +0 -37
- package/lib/services/collab/index.js +0 -468
- package/test.js +0 -38
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
var pubNub = require(
|
|
2
|
-
var
|
|
1
|
+
var pubNub = require('pubnub');
|
|
2
|
+
var request = require('superagent');
|
|
3
|
+
var EventEmitter = require('events').EventEmitter;
|
|
3
4
|
var helpers = require('../../helpers');
|
|
4
5
|
|
|
5
6
|
var PUSHXError = helpers.errors.PUSHXError;
|
|
@@ -12,200 +13,426 @@ var CHANNEL_DELIMITER = '$';
|
|
|
12
13
|
* implementation details - allowing future switch (to a different Saas provider).
|
|
13
14
|
*/
|
|
14
15
|
module.exports = function () {
|
|
15
|
-
|
|
16
|
+
'use strict';
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
/** ====== MODULE GLOBALS */
|
|
19
|
+
var _pubnubClient; //SAAS provider client SDK (PubNub).
|
|
20
|
+
var _eventEmitter = new EventEmitter();
|
|
21
|
+
var _userOptions;
|
|
22
|
+
var _globalSubscription = [];
|
|
23
|
+
var _globalSubscriptionStatus = {};
|
|
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
|
|
|
27
|
-
|
|
35
|
+
/** ====== UTILITY FUNCTIONS */
|
|
28
36
|
|
|
29
37
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
if(channelObj.accountid) { channelContext.push('a-' + channelObj.accountid); }
|
|
46
|
-
else {
|
|
47
|
-
if(channelObj.orgid) { channelContext.push('o-' + channelObj.orgid); }
|
|
48
|
-
if(channelObj.userid) { channelContext.push('u-' + channelObj.userid); }
|
|
49
|
-
if(channelObj.productid) { channelContext.push('p-' + channelObj.productid); }
|
|
50
|
-
if(channelObj.classid) { channelContext.push('c-' + channelObj.classid); }
|
|
51
|
-
}
|
|
52
|
-
pubNubChannel = channelContext.join(CHANNEL_DELIMITER) + CHANNEL_DELIMITER +
|
|
53
|
-
channelObj.channel;
|
|
54
|
-
if(!_globalSubscription.includes(pubNubChannel)) {
|
|
55
|
-
_globalSubscription.push(pubNubChannel);
|
|
56
|
-
_globalSubscriptionStatus[pubNubChannel] = {
|
|
57
|
-
status: 'pending'
|
|
58
|
-
};
|
|
59
|
-
_eventEmitter.on(pubNubChannel, handler);
|
|
60
|
-
_subscribeToPubNubChannels(pubNubChannel);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
else if(channelObj.channel === 'pushx_status' && ! bStatusSubscribed) {
|
|
64
|
-
_eventEmitter.on(channelObj.channel, handler);
|
|
65
|
-
bStatusSubscribed = true;
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
"getMySubscriptionStatus": __getMySubscriptionStatus
|
|
69
|
-
};
|
|
70
|
-
};
|
|
38
|
+
/**
|
|
39
|
+
* Call this function to make a new client adaptor.
|
|
40
|
+
This adapter exposes functions to send message, update user state etc.
|
|
41
|
+
* @return (object) : client adapter.
|
|
42
|
+
*/
|
|
43
|
+
var _constructClientAdaptor = function () {
|
|
44
|
+
//Returning the adaptor (Plain Javascript object)
|
|
45
|
+
return {
|
|
46
|
+
'on': function (channelObj, handler) {
|
|
47
|
+
// If PubNub fails, we will fetch the events from this timestamp
|
|
48
|
+
_startTimestampForPolling = Date.now();
|
|
49
|
+
|
|
50
|
+
var pubNubChannel;
|
|
51
|
+
var channelContext = [];
|
|
71
52
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
53
|
+
if((channelObj.orgid || channelObj.userid) || channelObj.accountid ||
|
|
54
|
+
channelObj.productid || channelObj.classid)
|
|
55
|
+
{
|
|
56
|
+
if(channelObj.accountid) { channelContext.push('a-' + channelObj.accountid); }
|
|
57
|
+
else {
|
|
58
|
+
if(channelObj.orgid) { channelContext.push('o-' + channelObj.orgid); }
|
|
59
|
+
if(channelObj.userid) { channelContext.push('u-' + channelObj.userid); }
|
|
60
|
+
if(channelObj.productid) { channelContext.push('p-' + channelObj.productid); }
|
|
61
|
+
if(channelObj.classid) { channelContext.push('c-' + channelObj.classid); }
|
|
62
|
+
}
|
|
63
|
+
pubNubChannel = channelContext.join(CHANNEL_DELIMITER) + CHANNEL_DELIMITER +
|
|
64
|
+
channelObj.channel;
|
|
65
|
+
if(!_globalSubscription.includes(pubNubChannel)) {
|
|
66
|
+
_globalSubscription.push(pubNubChannel);
|
|
67
|
+
_globalSubscriptionStatus[pubNubChannel] = {
|
|
68
|
+
status: 'pending'
|
|
69
|
+
};
|
|
70
|
+
_eventEmitter.on(pubNubChannel, handler);
|
|
71
|
+
_subscribeToPubNubChannels(pubNubChannel);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else if(channelObj.channel === 'pushx_status' && ! bStatusSubscribed) {
|
|
75
|
+
_eventEmitter.on(channelObj.channel, handler);
|
|
76
|
+
bStatusSubscribed = true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Clean up the old events
|
|
80
|
+
_checkOldBubbledEvents();
|
|
81
|
+
},
|
|
82
|
+
'getMySubscriptionStatus': __getMySubscriptionStatus
|
|
76
83
|
};
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
var _translatePubnubMessage = function (pubNubEventData) {
|
|
87
|
+
var subscribedChannel = pubNubEventData.subscribedChannel;
|
|
88
|
+
var message = pubNubEventData.message;
|
|
89
|
+
_eventEmitter.emit(subscribedChannel, message);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
var _translatePubnubStatus = function(status, options) {
|
|
93
|
+
var channels = [], error, successObj;
|
|
77
94
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
break;
|
|
105
|
-
case "PNAccessDeniedCategory":
|
|
106
|
-
if(status.operation === "PNSubscribeOperation") {
|
|
107
|
-
var errorData = {
|
|
108
|
-
payload: JSON.parse(status.errorData.response.text).payload,
|
|
109
|
-
message: 'Forbidden: Subscription failed.',
|
|
110
|
-
errorDetails: {
|
|
111
|
-
operation: status.operation,
|
|
112
|
-
category: status.category,
|
|
113
|
-
statusCode: status.statusCode
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
channels = errorData.payload.channels;
|
|
117
|
-
for(var j in channels) {
|
|
118
|
-
if(_globalSubscriptionStatus[channels[j]]) {
|
|
119
|
-
_globalSubscriptionStatus[channels[j]].status = 'error';
|
|
120
|
-
_globalSubscriptionStatus[channels[j]].error = error;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
error = new PUSHXError(helpers.errors.ERROR_CATEGORY.PUSHX, errorData);
|
|
124
|
-
_eventEmitter.emit('pushx_status', error);
|
|
125
|
-
}
|
|
126
|
-
break;
|
|
127
|
-
case "PNBadRequestCategory":
|
|
128
|
-
case "PNNetworkDownCategory":
|
|
129
|
-
case "PNNetworkUpCategory":
|
|
130
|
-
error = {
|
|
131
|
-
message: "PushX Error", status: status.statusCode,
|
|
132
|
-
pushXError: status
|
|
133
|
-
};
|
|
134
|
-
error = new PUSHXError(helpers.errors.ERROR_CATEGORY.PUSHX, error);
|
|
135
|
-
_eventEmitter.emit('pushx_status', error);
|
|
136
|
-
break;
|
|
95
|
+
// If polling has been initiated, ignore all punnub status
|
|
96
|
+
if (bPollingInitiated) return;
|
|
97
|
+
|
|
98
|
+
switch (status.category) {
|
|
99
|
+
case 'PNConnectedCategory':
|
|
100
|
+
if(status.operation === 'PNSubscribeOperation') {
|
|
101
|
+
channels = status.subscribedChannels;
|
|
102
|
+
for(var i in channels) {
|
|
103
|
+
if(_globalSubscriptionStatus[channels[i]]) {
|
|
104
|
+
_globalSubscriptionStatus[channels[i]].status = 'subscribed';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
successObj = {
|
|
108
|
+
category: 'PUSHX',
|
|
109
|
+
type: 'CHANNEL_SUBSCRIPTION',
|
|
110
|
+
status: 'SUCCESS',
|
|
111
|
+
message: 'Success: Subscribed successfully.',
|
|
112
|
+
httpcode: 200,
|
|
113
|
+
data: {
|
|
114
|
+
payload: {
|
|
115
|
+
channels: status.subscribedChannels
|
|
116
|
+
},
|
|
117
|
+
message: 'Success: Subscribed successfully.'
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
_eventEmitter.emit('pushx_status', successObj);
|
|
137
121
|
}
|
|
138
|
-
|
|
122
|
+
break;
|
|
123
|
+
case 'PNAccessDeniedCategory':
|
|
124
|
+
if(status.operation === 'PNSubscribeOperation') {
|
|
125
|
+
var errorText = status.errorData.response && status.errorData.response.text;
|
|
126
|
+
var errorJSON = errorText ? JSON.parse(errorText) : undefined;
|
|
127
|
+
var errorData = {
|
|
128
|
+
payload: errorJSON && errorJSON.payload || status.errorData.payload,
|
|
129
|
+
message: 'Forbidden: Subscription failed.',
|
|
130
|
+
errorDetails: {
|
|
131
|
+
operation: status.operation,
|
|
132
|
+
category: status.category,
|
|
133
|
+
statusCode: status.statusCode
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
channels = errorData.payload.channels;
|
|
137
|
+
for(var j in channels) {
|
|
138
|
+
if(_globalSubscriptionStatus[channels[j]]) {
|
|
139
|
+
_globalSubscriptionStatus[channels[j]].status = 'error';
|
|
140
|
+
_globalSubscriptionStatus[channels[j]].error = error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
error = new PUSHXError(helpers.errors.ERROR_CATEGORY.PUSHX, errorData);
|
|
144
|
+
_eventEmitter.emit('pushx_status', error);
|
|
145
|
+
}
|
|
146
|
+
break;
|
|
147
|
+
case 'PNBadRequestCategory':
|
|
148
|
+
case 'PNNetworkDownCategory':
|
|
149
|
+
case 'PNNetworkUpCategory':
|
|
150
|
+
error = {
|
|
151
|
+
message: 'PushX Error', status: status.statusCode,
|
|
152
|
+
pushXError: status
|
|
153
|
+
};
|
|
154
|
+
error = new PUSHXError(helpers.errors.ERROR_CATEGORY.PUSHX, error);
|
|
155
|
+
_eventEmitter.emit('pushx_status', error);
|
|
156
|
+
break;
|
|
157
|
+
case 'PNNetworkIssuesCategory':
|
|
158
|
+
if(status.operation === 'PNSubscribeOperation') {
|
|
159
|
+
if(!options.accountId || !_userOptions.pollingEndpoint) {
|
|
160
|
+
error = {
|
|
161
|
+
message: 'Polling initiation error: Missing mandatory parameters to initiate polling operation - [accountId, pollingEndpoint]',
|
|
162
|
+
status: status.statusCode
|
|
163
|
+
};
|
|
164
|
+
error = new PUSHXError(helpers.errors.ERROR_CATEGORY.PUSHX, error);
|
|
165
|
+
_eventEmitter.emit('pushx_status', error);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
/**
|
|
170
|
+
* Handle network issue category status for 'subscription' opreration
|
|
171
|
+
* Start the events polling here.
|
|
172
|
+
*
|
|
173
|
+
* The wrapper supports multiple channels, but the APP currently uses a single channel only.
|
|
174
|
+
* Polling will also limited to a single channel.
|
|
175
|
+
*/
|
|
176
|
+
_pollingCounter = 0;
|
|
177
|
+
_pollForEvents();
|
|
178
|
+
bPollingInitiated = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// Handle network issue category status for other operations like 'unsubscription'
|
|
183
|
+
}
|
|
184
|
+
break;
|
|
185
|
+
case 'PNReconnectedCategory':
|
|
186
|
+
// Handle reconnected category status.
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
// Emit error for other status-category received from pubnub
|
|
190
|
+
error = {
|
|
191
|
+
message: 'PushX Error: unexpected error',
|
|
192
|
+
status: status.statusCode,
|
|
193
|
+
pushXError: status
|
|
194
|
+
};
|
|
195
|
+
error = new PUSHXError(helpers.errors.ERROR_CATEGORY.PUSHX, error);
|
|
196
|
+
_eventEmitter.emit('pushx_status', error);
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
};
|
|
139
200
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
201
|
+
var __getMySubscriptionStatus = function() {
|
|
202
|
+
return JSON.parse(JSON.stringify(_globalSubscriptionStatus));
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Sets up necessary subscriptions (Pub/Sub) to PUSH channels. To a large extent, subscriptions are
|
|
207
|
+
* driven the student's (instructor's) roster.
|
|
208
|
+
* @param {object} groups - Roster information, provided during initialization, wrapper.setup().
|
|
209
|
+
*/
|
|
210
|
+
var _subscribeToPubNubChannels = function (channel) {
|
|
211
|
+
_pubnubClient.subscribe({ // Calling Pubnub SDK
|
|
212
|
+
'channels': [channel]
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/** ###### END OF UTILITY FUNCTIONS ############ */
|
|
217
|
+
|
|
218
|
+
/** ====== Client Wrapper Member functions ==> Mapped to Public Methods */
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Initializes the library, and established a connection with the Saas/PUSH provider.
|
|
222
|
+
* Setup should be called only once i.e. ONE CONNECTION (on a page/tab) is allowed
|
|
223
|
+
* at a time. If called again, it will throw an error (failure callback).
|
|
224
|
+
*
|
|
225
|
+
* @param {object} userOptions - User auth key and pubnub credentials
|
|
226
|
+
* @returns PROMISE.
|
|
227
|
+
*/
|
|
228
|
+
var __setup = function (userOptions) {
|
|
229
|
+
|
|
230
|
+
var pubnubConfig = userOptions.pubnub;
|
|
231
|
+
pubnubConfig.uuid = userOptions.userid;
|
|
232
|
+
var accountId = userOptions.accountid;
|
|
233
|
+
var token = userOptions.token;
|
|
234
|
+
|
|
235
|
+
if (!_pubnubClient && pubnubConfig) {
|
|
236
|
+
_pubnubClient = new pubNub(pubnubConfig); //Connect with PubNub SDK
|
|
237
|
+
_pubnubClient.setToken(token);
|
|
238
|
+
processSetup();
|
|
239
|
+
} else {
|
|
240
|
+
return new Error('Already Initialized');
|
|
241
|
+
}
|
|
143
242
|
|
|
144
243
|
/**
|
|
145
|
-
*
|
|
146
|
-
* driven the student's (instructor's) roster.
|
|
147
|
-
* @param {object} groups - Roster information, provided during initialization, wrapper.setup().
|
|
244
|
+
* SYNC Function
|
|
148
245
|
*/
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
246
|
+
function processSetup() {
|
|
247
|
+
_userOptions = userOptions;
|
|
248
|
+
_pubnubClient.addListener({ //Setup Listeners (events will shows up after subscription)
|
|
249
|
+
'message': function (data) {
|
|
250
|
+
_translatePubnubMessage(data);
|
|
251
|
+
},
|
|
252
|
+
'status': function (status) {
|
|
253
|
+
var statusOptions = { accountId: accountId };
|
|
254
|
+
_translatePubnubStatus(status, statusOptions);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return _constructClientAdaptor();
|
|
259
|
+
}; //End of _setup()
|
|
260
|
+
|
|
261
|
+
var __cleanup = function () {
|
|
262
|
+
if (_pubnubClient) { //Skip cleanup if setup() was not called.
|
|
263
|
+
_pubnubClient.unsubscribeAll();
|
|
264
|
+
_pubnubClient.stop();
|
|
265
|
+
_globalSubscription = [];
|
|
266
|
+
bStatusSubscribed = false;
|
|
267
|
+
_globalSubscriptionStatus = {};
|
|
268
|
+
bPollingInitiated = false;
|
|
269
|
+
}
|
|
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()
|
|
153
294
|
};
|
|
154
295
|
|
|
155
|
-
|
|
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
|
+
}
|
|
156
301
|
|
|
157
|
-
|
|
302
|
+
var requestAPI = request.get(_userOptions.pollingEndpoint).query(params);
|
|
158
303
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
+
}
|
|
170
337
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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;
|
|
174
352
|
} else {
|
|
175
|
-
|
|
353
|
+
// Else, use exponential backoff
|
|
354
|
+
timeoutDelay = parseInt(Math.pow(1.3, _pollingCounter) * 10 * 1000, 10);
|
|
176
355
|
}
|
|
177
356
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
function processSetup() {
|
|
182
|
-
_userOptions = userOptions;
|
|
183
|
-
_pubnubClient.addListener({ //Setup Listeners (events will shows up after subscription)
|
|
184
|
-
"message": function (data) {
|
|
185
|
-
_translatePubnubMessage(data);
|
|
186
|
-
},
|
|
187
|
-
"status": function (status) {
|
|
188
|
-
_translatePubnubStatus(status);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
357
|
+
// Set timeout for next poll
|
|
358
|
+
if (timeoutDelay) {
|
|
359
|
+
_setTimeoutIDForPolling = setTimeout(_pollForEvents, timeoutDelay);
|
|
191
360
|
}
|
|
192
|
-
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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 = {};
|
|
202
406
|
}
|
|
203
|
-
_pubnubClient = undefined;
|
|
204
|
-
};
|
|
205
407
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
|
209
430
|
};
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
return { // Return public methods for the wrapper
|
|
434
|
+
'setup': __setup,
|
|
435
|
+
'cleanup': __cleanup
|
|
436
|
+
};
|
|
210
437
|
|
|
211
438
|
}; //End of Client Wrapper module
|