You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

analytics.js 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. * Handles the initialization of analytics.
  27. */
  28. class Analytics {
  29. constructor() {
  30. this._scriptURLs = Array.isArray(config.analyticsScriptUrls)
  31. ? config.analyticsScriptUrls : [];
  32. this._enabled = !!this._scriptURLs.length
  33. && !config.disableThirdPartyRequests;
  34. window.analyticsHandlers = [];
  35. const machineId = JitsiMeetJS.getMachineId();
  36. this._handlerConstructorOptions = {
  37. product: "lib-jitsi-meet",
  38. version: JitsiMeetJS.version,
  39. session: machineId,
  40. user: "uid-" + machineId
  41. };
  42. }
  43. /**
  44. * Returns whether analytics is enabled or not.
  45. * @returns {boolean} whether analytics is enabled or not.
  46. */
  47. isEnabled() {
  48. return this._enabled;
  49. }
  50. /**
  51. * Tries to load the scripts for the analytics handlers.
  52. * @returns {Promise} resolves with the handlers that have been
  53. * successfully loaded and rejects if there are no handlers loaded or the
  54. * analytics is disabled.
  55. */
  56. _loadHandlers() {
  57. if(!this.isEnabled()) {
  58. return Promise.reject(new Error("Analytics is disabled!"));
  59. }
  60. let handlersPromises = [];
  61. this._scriptURLs.forEach(url =>
  62. handlersPromises.push(
  63. loadScript(url).then(
  64. () => {
  65. return {type: "success"};
  66. },
  67. error => {
  68. return {type: "error", error, url};
  69. }))
  70. );
  71. return new Promise((resolve, reject) =>
  72. {
  73. Promise.all(handlersPromises).then(values => {
  74. values.forEach(el => {
  75. if(el.type === "error") {
  76. console.log("Fialed to load " + el.url);
  77. console.error(el.error);
  78. }
  79. });
  80. if(window.analyticsHandlers.length === 0) {
  81. reject(new Error("No analytics handlers available"));
  82. } else {
  83. let handlerInstances = [];
  84. window.analyticsHandlers.forEach(
  85. Handler => handlerInstances.push(
  86. new Handler(this._handlerConstructorOptions)));
  87. resolve(handlerInstances);
  88. }
  89. });
  90. });
  91. }
  92. /**
  93. * Loads the analytics scripts and inits JitsiMeetJS.analytics by setting
  94. * permanent properties and setting the handlers from the loaded scripts.
  95. * NOTE: Has to be used after JitsiMeetJS.init. Otherwise analytics will be
  96. * null.
  97. */
  98. init() {
  99. let analytics = JitsiMeetJS.analytics;
  100. if(!this.isEnabled() || !analytics)
  101. return;
  102. this._loadHandlers()
  103. .then(handlers => {
  104. let permanentProperties = {
  105. userAgent: navigator.userAgent,
  106. roomName: APP.conference.roomName
  107. };
  108. let {server, group} = APP.tokenData;
  109. if(server) {
  110. permanentProperties.server = server;
  111. }
  112. if(group) {
  113. permanentProperties.group = group;
  114. }
  115. analytics.addPermanentProperties(permanentProperties);
  116. analytics.setAnalyticsHandlers(handlers);
  117. }, error => analytics.dispose() && console.error(error));
  118. }
  119. }
  120. export default new Analytics();