metrics.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import storage from './storage';
  2. import { platform, locale } from './utils';
  3. import { sendMetrics } from './api';
  4. let appState = null;
  5. let experiment = null;
  6. const HOUR = 1000 * 60 * 60;
  7. const events = [];
  8. let session_id = Date.now();
  9. const lang = locale();
  10. export default function initialize(state, emitter) {
  11. appState = state;
  12. emitter.on('DOMContentLoaded', () => {
  13. experiment = storage.enrolled;
  14. if (!appState.user.firstAction) {
  15. appState.user.firstAction =
  16. appState.route === '/' ? 'upload' : 'download';
  17. }
  18. const query = appState.query;
  19. addEvent('client_visit', {
  20. entrypoint: appState.route === '/' ? 'upload' : 'download',
  21. referrer: document.referrer,
  22. utm_campaign: query.utm_campaign,
  23. utm_content: query.utm_content,
  24. utm_medium: query.utm_medium,
  25. utm_source: query.utm_source,
  26. utm_term: query.utm_term
  27. });
  28. });
  29. emitter.on('experiment', experimentEvent);
  30. window.addEventListener('unload', submitEvents);
  31. }
  32. function sizeOrder(n) {
  33. return Math.floor(Math.log10(n));
  34. }
  35. function submitEvents() {
  36. if (navigator.doNotTrack === '1') {
  37. return;
  38. }
  39. sendMetrics(
  40. new Blob(
  41. [
  42. JSON.stringify({
  43. now: Date.now(),
  44. session_id,
  45. lang,
  46. platform: platform(),
  47. events
  48. })
  49. ],
  50. { type: 'text/plain' } // see http://crbug.com/490015
  51. )
  52. );
  53. events.splice(0);
  54. }
  55. async function addEvent(event_type, event_properties) {
  56. const user_id = await appState.user.metricId();
  57. const device_id = await appState.user.deviceId();
  58. const ab_id = Object.keys(experiment)[0];
  59. if (ab_id) {
  60. event_properties.experiment = ab_id;
  61. event_properties.variant = experiment[ab_id];
  62. }
  63. events.push({
  64. device_id,
  65. event_properties,
  66. event_type,
  67. time: Date.now(),
  68. user_id,
  69. user_properties: {
  70. anonymous: !appState.user.loggedIn,
  71. first_action: appState.user.firstAction,
  72. active_count: storage.files.length
  73. }
  74. });
  75. if (events.length === 25) {
  76. submitEvents();
  77. }
  78. }
  79. function cancelledUpload(archive, duration) {
  80. return addEvent('client_upload', {
  81. download_limit: archive.dlimit,
  82. duration: sizeOrder(duration),
  83. file_count: archive.numFiles,
  84. password_protected: !!archive.password,
  85. size: sizeOrder(archive.size),
  86. status: 'cancel',
  87. time_limit: archive.timeLimit
  88. });
  89. }
  90. function completedUpload(archive, duration) {
  91. return addEvent('client_upload', {
  92. download_limit: archive.dlimit,
  93. duration: sizeOrder(duration),
  94. file_count: archive.numFiles,
  95. password_protected: !!archive.password,
  96. size: sizeOrder(archive.size),
  97. status: 'ok',
  98. time_limit: archive.timeLimit
  99. });
  100. }
  101. function stoppedUpload(archive, duration = 0) {
  102. return addEvent('client_upload', {
  103. download_limit: archive.dlimit,
  104. duration: sizeOrder(duration),
  105. file_count: archive.numFiles,
  106. password_protected: !!archive.password,
  107. size: sizeOrder(archive.size),
  108. status: 'error',
  109. time_limit: archive.timeLimit
  110. });
  111. }
  112. function stoppedDownload(params) {
  113. return addEvent('client_download', {
  114. duration: sizeOrder(params.duration),
  115. password_protected: params.password_protected,
  116. size: sizeOrder(params.size),
  117. status: 'error'
  118. });
  119. }
  120. function completedDownload(params) {
  121. return addEvent('client_download', {
  122. duration: sizeOrder(params.duration),
  123. password_protected: params.password_protected,
  124. size: sizeOrder(params.size),
  125. status: 'ok'
  126. });
  127. }
  128. function deletedUpload(ownedFile) {
  129. return addEvent('client_delete', {
  130. age: Math.floor((Date.now() - ownedFile.createdAt) / HOUR),
  131. downloaded: ownedFile.dtotal > 0,
  132. status: 'ok'
  133. });
  134. }
  135. function experimentEvent(params) {
  136. return addEvent('client_experiment', params);
  137. }
  138. function submittedSignup(params) {
  139. return addEvent('client_login', {
  140. status: 'ok',
  141. trigger: params.trigger
  142. });
  143. }
  144. function canceledSignup(params) {
  145. return addEvent('client_login', {
  146. status: 'cancel',
  147. trigger: params.trigger
  148. });
  149. }
  150. function loggedOut(params) {
  151. addEvent('client_logout', {
  152. status: 'ok',
  153. trigger: params.trigger
  154. });
  155. // flush events and start new anon session
  156. submitEvents();
  157. session_id = Date.now();
  158. }
  159. export {
  160. cancelledUpload,
  161. stoppedUpload,
  162. completedUpload,
  163. deletedUpload,
  164. stoppedDownload,
  165. completedDownload,
  166. submittedSignup,
  167. canceledSignup,
  168. loggedOut
  169. };