comprodls-sdk 2.89.0 → 2.90.0-qa
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 +5937 -8432
- package/dist/comprodls-sdk.min.js +15 -1
- package/lib/comprodls.js +39 -57
- package/lib/config/index.js +171 -199
- 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 +73 -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 +238 -896
- package/lib/services/authextn/index.js +50 -150
- 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 +74 -85
- package/lib/services/pub/index.js +159 -234
- package/lib/services/pushX/index.js +29 -33
- package/lib/services/pushX/pubnubClientWrapper.js +398 -398
- package/lib/services/rules/index.js +14 -67
- package/lib/services/spaces/index.js +106 -294
- package/lib/services/spacesextn/index.js +4 -24
- package/lib/services/superuser/index.js +21 -36
- package/lib/services/taxonomy/index.js +27 -57
- package/lib/services/workflows/index.js +37 -98
- package/lib/services/xapi/index.js +6 -125
- package/lib/token/index.js +73 -67
- package/lib/token/validations.js +45 -48
- package/package.json +1 -2
- 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
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var pubNub = require(
|
|
1
|
+
var pubNub = require('pubnub');
|
|
2
2
|
var request = require('superagent');
|
|
3
|
-
var EventEmitter = require(
|
|
3
|
+
var EventEmitter = require('events').EventEmitter;
|
|
4
4
|
var helpers = require('../../helpers');
|
|
5
5
|
|
|
6
6
|
var PUSHXError = helpers.errors.PUSHXError;
|
|
@@ -13,426 +13,426 @@ var CHANNEL_DELIMITER = '$';
|
|
|
13
13
|
* implementation details - allowing future switch (to a different Saas provider).
|
|
14
14
|
*/
|
|
15
15
|
module.exports = function () {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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;
|
|
94
|
-
|
|
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);
|
|
121
|
-
}
|
|
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
|
-
};
|
|
200
|
-
|
|
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
|
-
});
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
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;
|
|
32
|
+
|
|
33
|
+
/** ###### END OF MODULE GLOBALS */
|
|
34
|
+
|
|
35
|
+
/** ====== UTILITY FUNCTIONS */
|
|
36
|
+
|
|
37
|
+
|
|
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 = [];
|
|
52
|
+
|
|
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
|
|
214
83
|
};
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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;
|
|
94
|
+
|
|
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);
|
|
241
121
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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);
|
|
257
145
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
+
}
|
|
269
180
|
}
|
|
270
|
-
|
|
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;
|
|
181
|
+
else {
|
|
182
|
+
// Handle network issue category status for other operations like 'unsubscription'
|
|
281
183
|
}
|
|
282
|
-
|
|
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
|
+
};
|
|
200
|
+
|
|
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
|
+
}
|
|
283
242
|
|
|
284
243
|
/**
|
|
285
|
-
*
|
|
244
|
+
* SYNC Function
|
|
286
245
|
*/
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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;
|
|
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);
|
|
300
255
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
-
});
|
|
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()
|
|
363
294
|
};
|
|
364
295
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
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
|
+
}
|
|
375
330
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
var eventId = event.pk + '_' + event.sk;
|
|
331
|
+
// Bubble the received events
|
|
332
|
+
_bubblePolledEvents(response.body);
|
|
379
333
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
334
|
+
// Increase the counter
|
|
335
|
+
_pollingCounter++;
|
|
336
|
+
}
|
|
383
337
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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);
|
|
387
355
|
}
|
|
388
356
|
|
|
389
|
-
//
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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
407
|
|
|
408
|
-
|
|
408
|
+
var oldEventIds = Object.keys(oldEvents);
|
|
409
409
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
413
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
414
|
+
if (oldEvents[oldEventId] < _startTimestampForPolling) {
|
|
415
|
+
delete oldEvents[oldEventId];
|
|
417
416
|
}
|
|
417
|
+
}
|
|
418
418
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
} else {
|
|
424
|
-
oldEvents = {};
|
|
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));
|
|
425
422
|
}
|
|
423
|
+
} else {
|
|
424
|
+
oldEvents = {};
|
|
425
|
+
}
|
|
426
426
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
};
|
|
427
|
+
return {
|
|
428
|
+
key: sessionStorageKey,
|
|
429
|
+
events: oldEvents
|
|
431
430
|
};
|
|
431
|
+
};
|
|
432
432
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
433
|
+
return { // Return public methods for the wrapper
|
|
434
|
+
'setup': __setup,
|
|
435
|
+
'cleanup': __cleanup
|
|
436
|
+
};
|
|
437
437
|
|
|
438
438
|
}; //End of Client Wrapper module
|