detect-user-session-start.mjs (2861B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 import { 6 actionCreators as ac, 7 actionTypes as at, 8 } from "../../common/Actions.mjs"; 9 import { perfService as perfSvc } from "./perf-service.mjs"; 10 11 const VISIBLE = "visible"; 12 const VISIBILITY_CHANGE_EVENT = "visibilitychange"; 13 14 export class DetectUserSessionStart { 15 constructor(store, options = {}) { 16 this._store = store; 17 // Overrides for testing 18 this.document = options.document || globalThis.document; 19 this._perfService = options.perfService || perfSvc; 20 this._onVisibilityChange = this._onVisibilityChange.bind(this); 21 } 22 23 /** 24 * sendEventOrAddListener - Notify immediately if the page is already visible, 25 * or else set up a listener for when visibility changes. 26 * This is needed for accurate session tracking for telemetry, 27 * because tabs are pre-loaded. 28 */ 29 sendEventOrAddListener() { 30 if (this.document.visibilityState === VISIBLE) { 31 // If the document is already visible, to the user, send a notification 32 // immediately that a session has started. 33 this._sendEvent(); 34 } else { 35 // If the document is not visible, listen for when it does become visible. 36 this.document.addEventListener( 37 VISIBILITY_CHANGE_EVENT, 38 this._onVisibilityChange 39 ); 40 } 41 } 42 43 /** 44 * _sendEvent - Sends a message to the main process to indicate the current 45 * tab is now visible to the user, includes the 46 * visibility_event_rcvd_ts time in ms from the UNIX epoch. 47 */ 48 _sendEvent() { 49 this._perfService.mark("visibility_event_rcvd_ts"); 50 51 try { 52 let visibility_event_rcvd_ts = 53 this._perfService.getMostRecentAbsMarkStartByName( 54 "visibility_event_rcvd_ts" 55 ); 56 57 this._store.dispatch( 58 ac.AlsoToMain({ 59 type: at.SAVE_SESSION_PERF_DATA, 60 data: { 61 visibility_event_rcvd_ts, 62 window_inner_width: window.innerWidth, 63 window_inner_height: window.innerHeight, 64 }, 65 }) 66 ); 67 } catch (ex) { 68 // If this failed, it's likely because the `privacy.resistFingerprinting` 69 // pref is true. We should at least not blow up. 70 } 71 } 72 73 /** 74 * _onVisibilityChange - If the visibility has changed to visible, sends a notification 75 * and removes the event listener. This should only be called once per tab. 76 */ 77 _onVisibilityChange() { 78 if (this.document.visibilityState === VISIBLE) { 79 this._sendEvent(); 80 this.document.removeEventListener( 81 VISIBILITY_CHANGE_EVENT, 82 this._onVisibilityChange 83 ); 84 } 85 } 86 }