Browse Source

feat(Analytics): Multiple analytics handlers support

j8
hristoterezov 8 years ago
parent
commit
dc0a7e7628
5 changed files with 139 additions and 30 deletions
  1. 3
    1
      analytics.js
  2. 7
    23
      conference.js
  3. 128
    0
      modules/analytics/analytics.js
  4. 1
    1
      modules/config/URLProcessor.js
  5. 0
    5
      modules/settings/Settings.js

+ 3
- 1
analytics.js View File

@@ -27,5 +27,7 @@
27 27
         action + '.' + data.browserName, label, value);
28 28
   };
29 29
 
30
-  ctx.Analytics = Analytics;
30
+  if(typeof ctx.analyticsHandlers === "undefined")
31
+    ctx.analyticsHandlers = [];
32
+  ctx.analyticsHandlers.push(Analytics);
31 33
 }(window));

+ 7
- 23
conference.js View File

@@ -13,6 +13,8 @@ import {reportError} from './modules/util/helpers';
13 13
 import UIEvents from './service/UI/UIEvents';
14 14
 import UIUtil from './modules/UI/util/UIUtil';
15 15
 
16
+import analytics from './modules/analytics/analytics';
17
+
16 18
 const ConnectionEvents = JitsiMeetJS.events.connection;
17 19
 const ConnectionErrors = JitsiMeetJS.errors.connection;
18 20
 
@@ -438,26 +440,6 @@ function disconnect() {
438 440
     return Promise.resolve();
439 441
 }
440 442
 
441
-/**
442
- * Set permanent properties to analytics.
443
- * NOTE: Has to be used after JitsiMeetJS.init. Otherwise analytics will be
444
- * null.
445
- */
446
-function setAnalyticsPermanentProperties() {
447
-    let permanentProperties = {
448
-        userAgent: navigator.userAgent,
449
-        roomName: APP.conference.roomName
450
-    };
451
-    let {server, group} = APP.tokenData;
452
-    if(server) {
453
-        permanentProperties.server = server;
454
-    }
455
-    if(group) {
456
-        permanentProperties.group = group;
457
-    }
458
-    JitsiMeetJS.analytics.addPermanentProperties(permanentProperties);
459
-}
460
-
461 443
 export default {
462 444
     isModerator: false,
463 445
     audioMuted: false,
@@ -504,9 +486,11 @@ export default {
504 486
             };
505 487
         }
506 488
 
507
-        return JitsiMeetJS.init(config)
508
-            .then(() => {
509
-                setAnalyticsPermanentProperties();
489
+        return JitsiMeetJS.init(
490
+            Object.assign(
491
+                {enableAnalyticsLogging: analytics.isEnabled()}, config)
492
+            ).then(() => {
493
+                analytics.init();
510 494
                 return createInitialLocalTracksAndConnect(options.roomName);
511 495
             }).then(([tracks, con]) => {
512 496
                 console.log('initialized with %s local tracks', tracks.length);

+ 128
- 0
modules/analytics/analytics.js View File

@@ -0,0 +1,128 @@
1
+/* global JitsiMeetJS, config, APP */
2
+/**
3
+ * Load the integration of a third-party analytics API such as Google
4
+ * Analytics. Since we cannot guarantee the quality of the third-party service
5
+ * (e.g. their server may take noticeably long time to respond), it is in our
6
+ * best interest (in the sense that the intergration of the analytics API is
7
+ * important to us but not enough to allow it to prevent people from joining
8
+ * a conference) to download the API asynchronously. Additionally, Google
9
+ * Analytics will download its implementation asynchronously anyway so it makes
10
+ * sense to append the loading on our side rather than prepend it.
11
+ * @param {string} url the url to be loaded
12
+ * @returns {Promise} resolved with no arguments when the script is loaded and
13
+ * rejected with the error from JitsiMeetJS.ScriptUtil.loadScript method
14
+ */
15
+function loadScript(url) {
16
+    return new Promise((resolve, reject) =>
17
+        JitsiMeetJS.util.ScriptUtil.loadScript(
18
+            url,
19
+            /* async */ true,
20
+            /* prepend */ false,
21
+            /* relativeURL */ false,
22
+            /* loadCallback */ () => resolve(),
23
+            /* errorCallback */ error => reject(error)));
24
+}
25
+
26
+/**
27
+ * Handles the initialization of analytics.
28
+ */
29
+class Analytics {
30
+    constructor() {
31
+        this._scriptURLs = Array.isArray(config.analyticsScriptUrls)
32
+            ? config.analyticsScriptUrls : [];
33
+        this._enabled = !!this._scriptURLs.length
34
+            && !config.disableThirdPartyRequests;
35
+        window.analyticsHandlers = [];
36
+        const machineId = JitsiMeetJS.getMachineId();
37
+        this._handlerConstructorOptions = {
38
+            product: "lib-jitsi-meet",
39
+            version: JitsiMeetJS.version,
40
+            session: machineId,
41
+            user:  "uid-" + machineId
42
+        };
43
+    }
44
+
45
+    /**
46
+     * Returns whether analytics is enabled or not.
47
+     * @returns {boolean} whether analytics is enabled or not.
48
+     */
49
+    isEnabled() {
50
+        return this._enabled;
51
+    }
52
+
53
+    /**
54
+     * Tries to load the scripts for the analytics handlers.
55
+     * @returns {Promise} resolves with the handlers that have been
56
+     * successfully loaded and rejects if there are no handlers loaded or the
57
+     * analytics is disabled.
58
+     */
59
+    _loadHandlers() {
60
+        if(!this.isEnabled()) {
61
+            return Promise.reject(new Error("Analytics is disabled!"));
62
+        }
63
+        let handlersPromises = [];
64
+        this._scriptURLs.forEach(url =>
65
+            handlersPromises.push(
66
+                loadScript(url).then(
67
+                    () => {
68
+                        return {type: "success"};
69
+                    },
70
+                    error => {
71
+                        return {type: "error", error, url};
72
+                    }))
73
+        );
74
+        return new Promise((resolve, reject) =>
75
+        {
76
+            Promise.all(handlersPromises).then(values => {
77
+                values.forEach(el => {
78
+                    if(el.type === "error") {
79
+                        console.log("Fialed to load " + el.url);
80
+                        console.error(el.error);
81
+                    }
82
+                });
83
+
84
+                if(window.analyticsHandlers.length === 0) {
85
+                    reject(new Error("No analytics handlers available"));
86
+                } else {
87
+                    let handlerInstances = [];
88
+                    window.analyticsHandlers.forEach(
89
+                        Handler => handlerInstances.push(
90
+                            new Handler(this._handlerConstructorOptions)));
91
+                    resolve(handlerInstances);
92
+                }
93
+            });
94
+        });
95
+    }
96
+
97
+    /**
98
+     * Loads the analytics scripts and inits JitsiMeetJS.analytics by setting
99
+     * permanent properties and setting the handlers from the loaded scripts.
100
+     * NOTE: Has to be used after JitsiMeetJS.init. Otherwise analytics will be
101
+     * null.
102
+     */
103
+    init() {
104
+        let analytics = JitsiMeetJS.analytics;
105
+        if(!this.isEnabled() || !analytics)
106
+            return;
107
+
108
+        this._loadHandlers()
109
+            .then(handlers => {
110
+                let permanentProperties = {
111
+                    userAgent: navigator.userAgent,
112
+                    roomName: APP.conference.roomName
113
+                };
114
+                let {server, group} = APP.tokenData;
115
+                if(server) {
116
+                    permanentProperties.server = server;
117
+                }
118
+                if(group) {
119
+                    permanentProperties.group = group;
120
+                }
121
+                analytics.addPermanentProperties(permanentProperties);
122
+                analytics.setAnalyticsHandlers(handlers);
123
+            }, error => analytics.dispose() && console.error(error));
124
+
125
+    }
126
+}
127
+
128
+export default new Analytics();

+ 1
- 1
modules/config/URLProcessor.js View File

@@ -38,7 +38,7 @@ var URLProcessor = {
38 38
                 confKey = key.substr("config.".length);
39 39
 
40 40
                 // prevent passing some parameters which can inject scripts
41
-                if (confKey === 'analyticsScriptUrl'
41
+                if (confKey === 'analyticsScriptUrls'
42 42
                     || confKey === 'callStatsCustomScriptUrl')
43 43
                     continue;
44 44
 

+ 0
- 5
modules/settings/Settings.js View File

@@ -9,11 +9,6 @@ function generateUniqueId() {
9 9
     return _p8() + _p8() + _p8() + _p8();
10 10
 }
11 11
 
12
-if (!jitsiLocalStorage.getItem("jitsiMeetId")) {
13
-    jitsiLocalStorage.setItem("jitsiMeetId",generateUniqueId());
14
-    console.log("generated id", jitsiLocalStorage.getItem("jitsiMeetId"));
15
-}
16
-
17 12
 let avatarUrl = '';
18 13
 
19 14
 let email = UIUtil.unescapeHtml(jitsiLocalStorage.getItem("email") || '');

Loading…
Cancel
Save