comprodls-sdk 2.43.0 → 2.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,557 +0,0 @@
1
- var q = require('q');
2
- var pubNub = require("pubnub");
3
-
4
- var sessionManager = require('./sessionStorage');
5
- var EventEmitter = require("events").EventEmitter;
6
- var _und = require('underscore');
7
-
8
- var EVENTS = {
9
- //Events to emit
10
- "USER_CHANGED": "presenceupdate", //Presense update (changes only)
11
- "COLLAB_EVENT": "collab", //Collaboration event (Message / Post / Announcement)
12
- "ACTIVITY_EVENT": "activity", //Assessment / Test / Activity event (Timeout)
13
- "JOB_EVENT": "job", //Job status
14
- "SYSTEM_EVENT": "systemevents", // comproDLS System Events
15
-
16
- //Events to listen
17
- "ACTIVEROOM": "activeroom"
18
- };
19
-
20
- var PRESENCE_ACTION = {
21
- "JOIN": "join",
22
- "LEAVE": "leave",
23
- "TIMEOUT": "timeout",
24
- "INTERVAL": "interval"
25
- };
26
-
27
- /**
28
- * Clientwrapper module.
29
- * Purpose - Wrapper around the Saas client SDK (PubNub). Abstracts the provider/vendor (PubNun) specific
30
- * implementation details - allowing future switch (to a different Saas provider).
31
- */
32
- module.exports = (function () {
33
- "use strict";
34
-
35
- /** ====== MODULE GLOBALS */
36
- var _pubnubClient; //SAAS provider client SDK (PubNub).
37
- var _notifications = new EventEmitter();
38
- var _currentUser;
39
- /**
40
- * A map to store the presence stats of all the users in my group (including me).
41
- *
42
- * @key {string} groupid - an identifier for unique group / sections.
43
- * @value {object} - information (userid, state, device_count) of occupants.
44
- */
45
- var _mapGroupPresence = {};
46
- var _mapSubscribePromise = {};
47
-
48
-
49
- /** ###### END OF MODULE GLOBALS */
50
-
51
- /** ====== UTILITY FUNCTIONS */
52
-
53
- /**
54
- * This function performs a deep cloning of a JSON object.
55
- *
56
- * @param data (JSON) : A json object that needs to be deep cloned.
57
- */
58
- var _deepClone = function(data) {
59
- return JSON.parse(JSON.stringify(data));
60
- };
61
-
62
-
63
- /**
64
- * This function is used to get device id.
65
- * @returns device id {integer} - device id for the current tab / device.
66
- */
67
- var _getDeviceId = function() {
68
- var sessionUserInfo;
69
- var sessionStorageData = sessionManager.getData(); // Get user information for the curret session.
70
- if(!sessionStorageData.error) {
71
- sessionUserInfo = sessionStorageData.data;
72
- }
73
- if(sessionUserInfo) {
74
- return sessionUserInfo.deviceId;
75
- } else {
76
- return Math.floor(100000 + Math.random() * 900000); // create new device id.
77
- }
78
- };
79
-
80
- var _notify = function(eventName, eventData) {
81
- _notifications.emit(eventName, eventData);
82
- };
83
-
84
-
85
- var _translatePubnubMessage = function(pubNubEventData) {
86
- var eventName = pubNubEventData.userMetadata.channel.split("push:")[1];
87
- var message = pubNubEventData.message;
88
- switch (eventName) {
89
- case EVENTS.COLLAB_EVENT:
90
- case EVENTS.ACTIVITY_EVENT:
91
- case EVENTS.JOB_EVENT:
92
- case EVENTS.SYSTEM_EVENT:
93
- _notify(eventName, message);
94
- break;
95
- }
96
- };
97
-
98
- var _translatePubnubPresence = function(pubNubEventData) {
99
- var eventName = EVENTS.USER_CHANGED;
100
- var orgId = _currentUser.orgId;
101
- var userId = pubNubEventData.uuid ? pubNubEventData.uuid.split(":")[0] : undefined;
102
- var deviceId = pubNubEventData.uuid ? pubNubEventData.uuid.split(":")[1] : undefined;
103
- var eventData = {
104
- orgid: orgId,
105
- actor: userId,
106
- context : 'everywhere'
107
- };
108
- var userInfo;
109
-
110
- switch (pubNubEventData.action){
111
- case PRESENCE_ACTION.JOIN:
112
- /**
113
- * Increment the device_count for existing user and create a new entry for
114
- * first time user login.
115
- */
116
- if(parseInt(deviceId) !== _currentUser.deviceId) {
117
- _updateGroupPresenceMap(PRESENCE_ACTION.JOIN, orgId, userId,
118
- pubNubEventData);
119
- userInfo = _mapGroupPresence[orgId].occupants[userId];
120
- if(userInfo.device_count === 1) {
121
- eventData.verb = 'online';
122
- _notify(eventName, eventData);
123
- }
124
- } else {
125
- // Presence event received for own device - IGNORING
126
- }
127
- break;
128
- case PRESENCE_ACTION.LEAVE:
129
- /**
130
- * Decrement the device_count for the user.
131
- */
132
- if(parseInt(deviceId) !== _currentUser.deviceId) {
133
- _updateGroupPresenceMap(PRESENCE_ACTION.LEAVE, orgId, userId,
134
- pubNubEventData);
135
- if(_mapGroupPresence[orgId].occupants[userId].device_count === 0) {
136
- /**
137
- * User left from all the devices. Propagate LEAVE event to reference app.
138
- * Cleaning _mapGroupPresence for this user.
139
- */
140
- delete _mapGroupPresence[orgId].occupants[userId];
141
- eventData.verb = 'offline';
142
- _notify(eventName, eventData);
143
- }
144
- } else {
145
- // Presence event received for own device - IGNORING
146
- }
147
- break;
148
- case PRESENCE_ACTION.TIMEOUT:
149
- /**
150
- * Decrement the device_count for the user.
151
- */
152
- if(parseInt(deviceId) !== _currentUser.deviceId) {
153
- _updateGroupPresenceMap(PRESENCE_ACTION.TIMEOUT, orgId, userId,
154
- pubNubEventData);
155
- if(_mapGroupPresence[orgId].occupants[userId].device_count === 0) {
156
- /**
157
- * User left / timed-out from all the devices. Propagate LEAVE event to
158
- * reference app. There is no difference between leave / timeout for
159
- * reference application.
160
- *
161
- * Cleaning _mapGroupPresence for this user.
162
- */
163
- delete _mapGroupPresence[orgId].occupants[userId];
164
- eventData.verb = 'offline';
165
- _notify(eventName, eventData);
166
- }
167
- } else {
168
- // Presence event received for own device - IGNORING
169
- }
170
- break;
171
- case PRESENCE_ACTION.INTERVAL:
172
- /**
173
- * An interval message is received from pubnub on reaching the ANNOUNCE-MAX
174
- * setting. If the number of occupants in a group is greater than or equal to
175
- * ANNOUNCE-MAX, then pubnub stops sending presence messages for actions JOIN,
176
- * LEAVE, TIMEOUT.
177
- *
178
- * The interval message has array of users (userids) that joined, left and
179
- * timed-out in a predefined interval.
180
- */
181
- _splitPresenceIntervalEvent(pubNubEventData);
182
- break;
183
- }
184
- };
185
-
186
-
187
- /**
188
- * This function creates a presence event.
189
- * The structure of this event is similar to pubnub's presence event.
190
- */
191
- var _constructPresenceEvent = function(event, userid, action) {
192
- return {
193
- "channel": event.channel, "subscription": event.subscription,
194
- "actualChannel": event.actualChannel,
195
- "subscribedChannel": event.subscribedChannel,
196
- "timetoken": event.timetoken,
197
- "occupancy": event.occupancy,
198
- "timestamp": event.timestamp,
199
- "action": action,
200
- "uuid": userid
201
- };
202
- };
203
-
204
- /**
205
- * This function is used to update the _mapGroupPresence for presence events.
206
- *
207
- * @param action - Presence action - [KOIN, LEAVE, TIMEOUT, INTERVAL].
208
- * @param channel - groupid of the group for which the presence event occured.
209
- * @param userid - (optional) userid of user for whom the event occured.
210
- * @param event - event data.
211
- */
212
- var _updateGroupPresenceMap = function(action, channel, userid) {
213
- switch(action) {
214
- case PRESENCE_ACTION.JOIN:
215
- if(_mapGroupPresence[channel].occupants[userid]) {
216
- // User already logged-in from other device.
217
- _mapGroupPresence[channel].occupants[userid].device_count += 1;
218
- } else { // First time log-in.
219
- _mapGroupPresence[channel].occupants[userid] = {
220
- "device_count": 1
221
- };
222
- }
223
- if(_mapGroupPresence[channel].occupants[userid].device_count === 1) {
224
- _mapGroupPresence[channel].occupancy += 1;
225
- }
226
- break;
227
- case PRESENCE_ACTION.LEAVE:
228
- case PRESENCE_ACTION.TIMEOUT:
229
- if(_mapGroupPresence[channel].occupants[userid]) {
230
- _mapGroupPresence[channel].occupants[userid].device_count -= 1;
231
- if(_mapGroupPresence[channel].occupants[userid].device_count === 0) {
232
- _mapGroupPresence[channel].occupancy -= 1;
233
- }
234
- }
235
- break;
236
- }
237
- };
238
-
239
- /**
240
- * This function translates the interval event for each user into individual
241
- * JOIN or LEAVE or TIMEOUT event as received from pubnub.
242
- *
243
- * For the reference application there are only four presence actions
244
- * [JOIN, LEAVE, TIMEOUT, STATE-CHANGE].
245
- */
246
- var _splitPresenceIntervalEvent = function(eventData) {
247
- var joinedUsers = eventData.join;
248
- var leftUsers = eventData.leave;
249
- var timeoutUsers = eventData.timeout;
250
- if(joinedUsers) {
251
- for(var i in joinedUsers) {
252
- var joinEvent = _constructPresenceEvent(eventData, joinedUsers[i], "join");
253
- _translatePubnubPresence(joinEvent);
254
- }
255
- }
256
- if(leftUsers) {
257
- for(var j in leftUsers) {
258
- var leftEvent = _constructPresenceEvent(eventData, leftUsers[j], "leave");
259
- _translatePubnubPresence(leftEvent);
260
- }
261
- }
262
- if(timeoutUsers) {
263
- for(var k in timeoutUsers) {
264
- var timeoutEvent = _constructPresenceEvent(eventData, timeoutUsers[k],
265
- "timeout");
266
- _translatePubnubPresence(timeoutEvent);
267
- }
268
- }
269
- };
270
-
271
- /**
272
- * Sets up necessary subscriptions (Pub/Sub) to PUSH channels. To a large extent, subscriptions are
273
- * driven the student's (instructor's) roster.
274
- * @param {object} groups - Roster information, provided during initialization, wrapper.setup().
275
- */
276
- var _subscribeToPubNubChannels = function(options) {
277
- _pubnubClient.subscribe({ // Calling Pubnub SDK
278
- "channels": [options.orgId],
279
- "withPresence": true
280
- });
281
- _pubnubClient.subscribe({ // Calling Pubnub SDK
282
- channels: [options.orgId + '.' + options.userId]
283
- });
284
- };
285
-
286
- /**
287
- * Call this function to make a new client adaptor.
288
- This adapter exposes functions to send message, update user state etc.
289
- * @return (object) : client adapter.
290
- */
291
- var _constructClientAdaptor = function() {
292
- //Returning the adaptor (Plain Javascript object)
293
- return {
294
- "getOnlineMembers": __getOnlineMembers,
295
- "joinClass": __joinClass,
296
- "joinProduct": __joinProduct,
297
- "joinGroup": __joinGroup,
298
- "on": _notifications.on.bind(_notifications),
299
- "emit": _notifications.emit.bind(_notifications)
300
- };
301
- };
302
-
303
- /**
304
- * This function converts unix epoch timestamp (ms) to pubnub's timetoken.
305
- *
306
- * @params {integer} timestamp - unix epoch timestamp (ms)
307
- *
308
- * @returns {string} - Pubnub's timetoken (timestamp = timetoken / 10000).
309
- */
310
- var _getPubnubTimeToken = function(timestamp) {
311
- return (timestamp * 10000).toString();
312
- };
313
-
314
- /**
315
- * This function converts pubnub's timetoken to unix epoch timestamp (ms).
316
- *
317
- * @params {string} timetoken - Pubnub's timetoken (timestamp = timetoken / 10000).
318
- *
319
- * @returns {integer} - unix epoch timestamp (ms).
320
- */
321
- var _getEpochTimestamp = function(timetoken) {
322
- return Math.round(parseInt(timetoken) / 10000);
323
- };
324
-
325
-
326
- /** ###### END OF UTILITY FUNCTIONS ############ */
327
-
328
- /** ====== Main Adapter Member functions ==> Mapped to Public Methods */
329
-
330
- /**
331
- * Gets Presence information (and state) for student's (instructor's) roster. Offline users are
332
- not support/included in this version.
333
- * @param {Array} groups - Roster information, provided during initialization, wrapper.setup().
334
- * @param {function} cbSuccess - (Optional) A function that accepts a single argument,
335
- which is an object having group level logged-in
336
- user's presence information.
337
- * @param {function} cbFailure - (Optional) A function that accepts an error object
338
- with statusCode and relavent message.
339
- */
340
- var __getOnlineMembers = function (groups, cbSuccess, cbFailure) {
341
- var responseObj = {};
342
- if(_und.isEmpty(_mapGroupPresence)) {
343
- /**
344
- * _mapGroupPresence is undefined, call pubnub for initialization.
345
- */
346
- _mapGroupPresence = {}; // Reset _mapGroupPresence.
347
- for(var i in groups) {
348
- _mapGroupPresence[groups[i]] = {
349
- "occupants": {}, "name": groups[i], "occupancy": 1
350
- };
351
- _mapGroupPresence[groups[i]].occupants[_currentUser.userId] = {
352
- "device_count": 1
353
- };
354
- }
355
- _pubnubClient.hereNow({
356
- "channels": groups,
357
- "includeUUIDs": true
358
- }, function(status, response) {
359
- if(status.error) {
360
- if(cbFailure && typeof cbFailure === "function") {
361
- cbFailure(status);
362
- }
363
- } else {
364
-
365
- if(cbSuccess && typeof cbSuccess === "function") {
366
- /**
367
- * Success callback parameter "response.channels" contains
368
- * information on the 'online' users in a group.
369
- * For Example:
370
- * {
371
- * "course_3": { // group name.
372
- * "occupants": [{ // user info array (array of objects).
373
- * "uuid": "102-<device id>" // Pubnub user uuid
374
- * }],
375
- * "name": "course_3", //group name
376
- * "occupancy": 1 //Total number of logged-in users in this group.
377
- * }
378
- * }
379
- */
380
- for(var channel in response.channels) {
381
- var users = response.channels[channel].occupants;
382
- for(var j in users) {
383
- var userid = users[j].uuid.split(":")[0];
384
- var device_id = users[j].uuid.split(":")[1];
385
- if(!_mapGroupPresence[channel].occupants[userid]) {
386
- _mapGroupPresence[channel].occupancy += 1;
387
- _mapGroupPresence[channel].occupants[userid] = {
388
- "device_count": 1
389
- };
390
- } else {
391
- if(parseInt(device_id) !== _currentUser.deviceId) {
392
- _mapGroupPresence[channel].occupants[userid].device_count += 1;
393
- }
394
- }
395
- }
396
- }
397
-
398
- /**
399
- * Translated _mapGroupPresence structure
400
- * {
401
- * "course_3": { // group name.
402
- * "occupants": { // user info array (array of objects).
403
- * "102": {
404
- * "state": { // state of a user.
405
- * "isTyping": false, //Typing state
406
- * "state": "AVAILABLE", //User online status
407
- * "first_name": "Albert",
408
- * "first_name": "Smith"
409
- * },
410
- * "device_count": 2
411
- * }
412
- * },
413
- * "name": "course_3", //group name
414
- * "occupancy": 1 //Total number of logged-in users in this group.
415
- * }
416
- * }
417
- */
418
-
419
- // Returning a copy of _mapGroupPresence
420
- for(var index in groups) {
421
- responseObj[groups[index]] = _mapGroupPresence[groups[index]];
422
- }
423
- cbSuccess(_deepClone(responseObj));
424
-
425
- }
426
- }
427
- });
428
- } else {
429
- // Returning a copy of _mapGroupPresence
430
- for(var index in groups) {
431
- responseObj[groups[index]] = _mapGroupPresence[groups[index]];
432
- }
433
- cbSuccess(_deepClone(responseObj));
434
- }
435
- };
436
-
437
- var __joinClass = function(uuid) {
438
- var dfd = q.defer();
439
- _mapSubscribePromise[_currentUser.orgId + '.' + uuid] = dfd;
440
- _pubnubClient.subscribe({ // Calling Pubnub SDK
441
- channels: [_currentUser.orgId + '.' + uuid]
442
- });
443
- return dfd.promise;
444
- };
445
-
446
- var __joinProduct = function(uuid) {
447
- var dfd = q.defer();
448
- _mapSubscribePromise[_currentUser.orgId + '.' + uuid] = dfd;
449
- _pubnubClient.subscribe({ // Calling Pubnub SDK
450
- channels: [_currentUser.orgId + '.' + uuid]
451
- });
452
- return dfd.promise;
453
- };
454
-
455
- var __joinGroup = function(uuid) {
456
- var dfd = q.defer();
457
- _mapSubscribePromise[_currentUser.orgId + '.' + uuid] = dfd;
458
- _pubnubClient.subscribe({ // Calling Pubnub SDK
459
- channels: [_currentUser.orgId + '.' + uuid]
460
- });
461
- return dfd.promise;
462
- };
463
-
464
- /** ###### End Of Main Adapter Member functions ############ */
465
-
466
- /** ====== Client Wrapper Member functions ==> Mapped to Public Methods */
467
-
468
- /**
469
- * Initializes the library, and established a connection with the Saas/PUSH provider. Setup should be
470
- * called only once i.e. ONE CONNECTION (on a page/tab) is allowed at a time. If called again, it will throw
471
- * an error (failure callback)
472
- * @param {string} grantEndPoint - The API endpoint that will return the roster data for the user.
473
- * @param {object} currentUser - (Optional) If this param is available, then the user is already logged in another
474
- * tab or has refreshed the tab. Grant API will not be called.
475
- * @param {object} mediaOptions - Contains media-stream-manager configurations (mode), publisher and subscriber
476
- * stream DOM id.
477
- * @param {function} cbSuccess - Success callback. A function that accepts a single argument which is the adapter
478
- object for further operations.
479
- * @param {function} cbFailure - Failure callback. A function that accepts a single argument which is an
480
- error object with more information
481
- */
482
- var __setup = function (currentUser) {
483
- var dfd = q.defer();
484
-
485
- var bInitialized = false; // Flag to track when PubNub SDK is initialized. By default FALSE.
486
- var deviceId, pubnubConfig = currentUser.pubnub;
487
-
488
- if(!_pubnubClient && currentUser) {
489
- deviceId = _getDeviceId();
490
- currentUser.deviceId = deviceId;
491
- /*pubnubConfig.authKey = currentUser.auth_token;*/
492
- pubnubConfig.uuid = currentUser.userId + ":" + deviceId;
493
- _pubnubClient = new pubNub(pubnubConfig); //Connect with PubNub SDK
494
- processSetup();
495
- }
496
-
497
- function processSetup() {
498
- _currentUser = currentUser;
499
- _pubnubClient.addListener({ //Setup Listeners (events will shows up after subscription)
500
- "message": function (data) { _translatePubnubMessage(data); },
501
- "presence": function (data) { _translatePubnubPresence(data); },
502
- "status": function (status) {
503
- switch(status.category) {
504
- /*
505
- Per PubNub Support...
506
-
507
- There is 'no' separate event to monitor a successful connection with PubNub.
508
- Instead we need to use PNConnectedCategory event post subscription to a
509
- channel.
510
- */
511
- case "PNConnectedCategory":
512
- if(!bInitialized) { // Initialization. The first Connect event is when PubNub is being initialized
513
- __getOnlineMembers(
514
- [currentUser.orgId],
515
- function success() {
516
- dfd.resolve(_constructClientAdaptor());
517
- },
518
- function failure(err) {
519
- dfd.reject(err);
520
- }
521
- );
522
- } else { //TODO Handle posting initialization Connect events
523
-
524
- }
525
- break;
526
- case "PNBadRequestCategory":
527
- case "PNAccessDeniedCategory":
528
- if(!bInitialized) { // Initialization. The first Connect event is when PubNub is being initialized
529
- dfd.reject(status);
530
- } else {
531
- //TODO Handle posting initialization Connect events
532
- }
533
- break;
534
- }
535
- }
536
- });
537
-
538
- _subscribeToPubNubChannels(currentUser); //Subscribe channels (roster)
539
- }
540
- return dfd.promise;
541
-
542
- }; //End of _setup()
543
-
544
- var __cleanup = function () {
545
- if(_pubnubClient) { //Skip cleanup if setup() was not called.
546
- _pubnubClient.unsubscribeAll();
547
- _pubnubClient.stop();
548
- sessionManager.removeData();
549
- }
550
- };
551
-
552
- return { // Return public methods for the wrapper
553
- "setup": __setup,
554
- "cleanup": __cleanup
555
- };
556
-
557
- })(); //End of Client Wrapper module
@@ -1,64 +0,0 @@
1
- module.exports = (function () {
2
- var _sessionStorageKey = "ComproDLS.PubnubClientWrapper.Session";
3
-
4
- /**
5
- * Function to check if the session storage supported by browser.
6
- */
7
- var __isSessionStorageSupported = function() {
8
- return (typeof(Storage) !== "undefined");
9
- };
10
-
11
- /**
12
- * Function to store data in session storage
13
- */
14
- var __setData = function(data) {
15
- if (__isSessionStorageSupported()) { // Web storage supported by browser.
16
- sessionStorage.setItem(_sessionStorageKey,
17
- JSON.stringify(data));
18
- return { "error": false };
19
- } else {
20
- return { "error": true };
21
- }
22
- };
23
-
24
- /**
25
- * Function to get data from session storage
26
- */
27
- var __getData = function() {
28
- if (__isSessionStorageSupported()) { // Web storage supported by browser.
29
- var sessionStorageData = JSON.parse(sessionStorage.getItem(_sessionStorageKey));
30
- if(sessionStorageData) {
31
- return {
32
- "error": false,
33
- "data": sessionStorageData
34
- };
35
- } else {
36
- return {
37
- "error": true,
38
- "message": "No data found in browser sessionStorage."
39
- };
40
- }
41
- } else {
42
- return { "error": true };
43
- }
44
- };
45
-
46
- /**
47
- * Function to remove data from session storage
48
- */
49
- var __removeData = function() {
50
- if (__isSessionStorageSupported()) { // Web storage supported by browser.
51
- sessionStorage.removeItem(_sessionStorageKey);
52
- return { "error": false };
53
- } else {
54
- return { "error": true };
55
- }
56
- };
57
-
58
- return {
59
- "setData": __setData,
60
- "getData": __getData,
61
- "removeData": __removeData,
62
- "isSessionStorageSupported" : __isSessionStorageSupported
63
- };
64
- }) ();