summaryrefslogtreecommitdiffstats
path: root/browser/components/pocket/content/pktTelemetry.sys.mjs
blob: 602d3bda251dc2dfbe375a8c48a5f262f8ae863a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";

const lazy = {};
ChromeUtils.defineModuleGetter(
  lazy,
  "PingCentre",
  "resource:///modules/PingCentre.jsm"
);
ChromeUtils.defineESModuleGetters(lazy, {
  pktApi: "chrome://pocket/content/pktApi.sys.mjs",
  TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.sys.mjs",
});

// List of namespaces for the structured ingestion system.
// They are defined in https://github.com/mozilla-services/mozilla-pipeline-schemas
const STRUCTURED_INGESTION_NAMESPACE_AS = "activity-stream";
const STRUCTURED_INGESTION_ENDPOINT_PREF =
  "browser.newtabpage.activity-stream.telemetry.structuredIngestion.endpoint";
// This is the topic for telemetry pings, used inside PingCentre.
const POCKET_TELEMETRY_TOPIC = "pocket";
const PREF_IMPRESSION_ID = "browser.newtabpage.activity-stream.impressionId";

XPCOMUtils.defineLazyGetter(lazy, "pingCentre", () => {
  return new lazy.PingCentre({ topic: POCKET_TELEMETRY_TOPIC });
});

export var pktTelemetry = {
  get structuredIngestionEndpointBase() {
    if (!this._structuredIngestionEndpointBase) {
      this._structuredIngestionEndpointBase = Services.prefs.getStringPref(
        STRUCTURED_INGESTION_ENDPOINT_PREF,
        ""
      );
    }
    return this._structuredIngestionEndpointBase;
  },

  get impressionId() {
    if (!this._impressionId) {
      this._impressionId = this.getOrCreateImpressionId();
    }
    return this._impressionId;
  },

  // Sets or gets the impression id that's use for Pocket impressions.
  // The impression id cannot be tied to a client id.
  // This is the same impression id used in newtab pocket impressions.
  getOrCreateImpressionId() {
    let impressionId = Services.prefs.getStringPref(PREF_IMPRESSION_ID, "");

    if (!impressionId) {
      impressionId = String(Services.uuid.generateUUID());
      Services.prefs.setStringPref(PREF_IMPRESSION_ID, impressionId);
    }
    return impressionId;
  },

  /**
   * createPingPayload - Create a ping for an impression stats
   *
   * @param  {ob} data The data object to be included in the ping.
   * @return {obj}    A telemetry ping
   */
  createPingPayload(data) {
    // experiments, locale, version, and release_channel are provided by pingCentre.
    // model and events is provided in the data param.
    return {
      ...data,
      impression_id: this.impressionId,
      pocket_logged_in_status: lazy.pktApi.isUserLoggedIn(),
      profile_creation_date: this._profileCreationDate(),
    };
  },

  _profileCreationDate() {
    return (
      lazy.TelemetryEnvironment.currentEnvironment.profile.resetDate ||
      lazy.TelemetryEnvironment.currentEnvironment.profile.creationDate
    );
  },

  _generateUUID() {
    return String(Services.uuid.generateUUID());
  },

  /**
   * Generates an endpoint for Structured Ingestion telemetry pipeline. Note that
   * Structured Ingestion requires a different endpoint for each ping. See more
   * details about endpoint schema at:
   * https://github.com/mozilla/gcp-ingestion/blob/master/docs/edge.md#postput-request
   */
  _generateStructuredIngestionEndpoint() {
    const uuid = this._generateUUID();
    // Structured Ingestion does not support the UUID generated by gUUIDGenerator,
    // because it contains leading and trailing braces. Need to trim them first.
    const docID = uuid.slice(1, -1);
    const extension = `${STRUCTURED_INGESTION_NAMESPACE_AS}/pocket-button/1/${docID}`;
    return `${this.structuredIngestionEndpointBase}/${extension}`;
  },

  /**
   * sendStructuredIngestionEvent - Sent a ping for an impression stats
   *
   * @param {ob} eventObject The data object to be included in the ping.
   */
  sendStructuredIngestionEvent(eventObject) {
    lazy.pingCentre.sendStructuredIngestionPing(
      eventObject,
      this._generateStructuredIngestionEndpoint(),
      STRUCTURED_INGESTION_NAMESPACE_AS
    );
  },
};