Skip to content
This repository has been archived by the owner on Feb 29, 2020. It is now read-only.

Commit

Permalink
PingCentre should set the cilentID, enforce a topic, and have an opti…
Browse files Browse the repository at this point in the history
…onal endpoint param.
  • Loading branch information
Marina Samuel committed Aug 11, 2017
1 parent 07d74ef commit 118d233
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 78 deletions.
87 changes: 56 additions & 31 deletions system-addon/lib/PingCentre.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.importGlobalProperties(["fetch"]);

XPCOMUtils.defineLazyModuleGetter(this, "ClientID",
"resource://gre/modules/ClientID.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/Console.jsm");

Expand All @@ -24,72 +26,95 @@ const FHR_UPLOAD_ENABLED_PREF = "datareporting.healthreport.uploadEnabled";
/**
* Observe various notifications and send them to a telemetry endpoint.
*
* @param {string} topic - a unique ID for users of PingCentre to distinguish
* their data on the server side.
* @param {string} pingEndpoint - the URL where the POST with data is sent.
* @param {Object} args - optional arguments
* @param {Function} args.prefInitHook - if present, will be called back
* inside the Prefs constructor. Typically used from tests
* to save off a pointer to a fake Prefs instance so that
* stubs and spies can be inspected by the test code.
*/
function PingCentre(args) {
let prefArgs = {};
if (args) {
if ("prefInitHook" in args) {
prefArgs.initHook = args.prefInitHook;
class PingCentre {
constructor(topic, pingEndpoint, args) {
let prefArgs = {};
if (args) {
if ("prefInitHook" in args) {
prefArgs.initHook = args.prefInitHook;
}
}

if (!topic) {
throw new Error("Must specify topic.");
}
}

this._prefs = new Preferences(prefArgs);
this._topic = topic;
this._prefs = new Preferences(prefArgs);
this._pingEndpoint = pingEndpoint || this._prefs.get(ENDPOINT_PREF);

this._enabled = this._prefs.get(TELEMETRY_PREF);
this._onTelemetryPrefChange = this._onTelemetryPrefChange.bind(this);
this._prefs.observe(TELEMETRY_PREF, this._onTelemetryPrefChange);
this._enabled = this._prefs.get(TELEMETRY_PREF);
this._onTelemetryPrefChange = this._onTelemetryPrefChange.bind(this);
this._prefs.observe(TELEMETRY_PREF, this._onTelemetryPrefChange);

this._fhrEnabled = this._prefs.get(FHR_UPLOAD_ENABLED_PREF);
this._onFhrPrefChange = this._onFhrPrefChange.bind(this);
this._prefs.observe(FHR_UPLOAD_ENABLED_PREF, this._onFhrPrefChange);
this._fhrEnabled = this._prefs.get(FHR_UPLOAD_ENABLED_PREF);
this._onFhrPrefChange = this._onFhrPrefChange.bind(this);
this._prefs.observe(FHR_UPLOAD_ENABLED_PREF, this._onFhrPrefChange);

this.logging = this._prefs.get(LOGGING_PREF);
this._onLoggingPrefChange = this._onLoggingPrefChange.bind(this);
this._prefs.observe(LOGGING_PREF, this._onLoggingPrefChange);
this.logging = this._prefs.get(LOGGING_PREF);
this._onLoggingPrefChange = this._onLoggingPrefChange.bind(this);
this._prefs.observe(LOGGING_PREF, this._onLoggingPrefChange);
}

this._pingEndpoint = this._prefs.get(ENDPOINT_PREF);
}
/**
* Lazily get the Telemetry id promise
*/
get telemetryClientId() {
Object.defineProperty(this, "telemetryClientId", {value: ClientID.getClientID()});
return this.telemetryClientId;
}

PingCentre.prototype = {
get enabled() {
return this._enabled && this._fhrEnabled;
},
}

_onLoggingPrefChange(prefVal) {
this.logging = prefVal;
},
}

_onTelemetryPrefChange(prefVal) {
this._enabled = prefVal;
},
}

_onFhrPrefChange(prefVal) {
this._fhrEnabled = prefVal;
},
}

async sendPing(data) {
if (!this.enabled) {
return Promise.resolve();
}

let clientID = data.client_id || await this.telemetryClientId;
const payload = Object.assign({
topic: this._topic,
client_id: clientID
}, data);

sendPing(data) {
if (this.logging) {
// performance related pings cause a lot of logging, so we mute them
if (data.action !== "activity_stream_performance") {
console.log(`TELEMETRY PING: ${JSON.stringify(data)}\n`); // eslint-disable-line no-console
console.log(`TELEMETRY PING: ${JSON.stringify(payload)}\n`); // eslint-disable-line no-console
}
}
if (!this.enabled) {
return Promise.resolve();
}
return fetch(this._pingEndpoint, {method: "POST", body: JSON.stringify(data)}).then(response => {

return fetch(this._pingEndpoint, {method: "POST", body: JSON.stringify(payload)}).then(response => {
if (!response.ok) {
Cu.reportError(`Ping failure with HTTP response code: ${response.status}`);
}
}).catch(e => {
Cu.reportError(`Ping failure with error: ${e}`);
});
},
}

uninit() {
try {
Expand All @@ -100,7 +125,7 @@ PingCentre.prototype = {
Cu.reportError(e);
}
}
};
}

this.PingCentre = PingCentre;
this.PingCentreConstants = {
Expand Down
39 changes: 14 additions & 25 deletions system-addon/lib/TelemetryFeed.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const {actionTypes: at, actionUtils: au} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
const {Prefs} = Cu.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {});

XPCOMUtils.defineLazyModuleGetter(this, "ClientID",
"resource://gre/modules/ClientID.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "perfService",
"resource://activity-stream/common/PerfService.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PingCentre",
Expand Down Expand Up @@ -79,19 +77,11 @@ this.TelemetryFeed = class TelemetryFeed {
this.saveSessionPerfData(port, data_to_save);
}

/**
* Lazily get the Telemetry id promise
*/
get telemetryClientId() {
Object.defineProperty(this, "telemetryClientId", {value: ClientID.getClientID()});
return this.telemetryClientId;
}

/**
* Lazily initialize PingCentre to send pings
*/
get pingCentre() {
Object.defineProperty(this, "pingCentre", {value: new PingCentre()});
Object.defineProperty(this, "pingCentre", {value: new PingCentre("activity-stream")});
return this.pingCentre;
}

Expand Down Expand Up @@ -155,10 +145,9 @@ this.TelemetryFeed = class TelemetryFeed {
* @param {string} id The portID of the session, if a session is relevant (optional)
* @return {obj} A telemetry ping
*/
async createPing(portID) {
createPing(portID) {
const appInfo = this.store.getState().App;
const ping = {
client_id: await this.telemetryClientId,
addon_version: appInfo.version,
locale: appInfo.locale,
user_prefs: this.userPreferences
Expand All @@ -184,9 +173,9 @@ this.TelemetryFeed = class TelemetryFeed {
* all the user specific IDs with "n/a" in the ping.
* @return {obj} A telemetry ping
*/
async createImpressionStats(action) {
createImpressionStats(action) {
let ping = Object.assign(
await this.createPing(au.getPortIdOfSender(action)),
this.createPing(au.getPortIdOfSender(action)),
action.data,
{action: "activity_stream_impression_stats"}
);
Expand All @@ -200,34 +189,34 @@ this.TelemetryFeed = class TelemetryFeed {
return ping;
}

async createUserEvent(action) {
createUserEvent(action) {
return Object.assign(
await this.createPing(au.getPortIdOfSender(action)),
this.createPing(au.getPortIdOfSender(action)),
action.data,
{action: "activity_stream_user_event"}
);
}

async createUndesiredEvent(action) {
createUndesiredEvent(action) {
return Object.assign(
await this.createPing(au.getPortIdOfSender(action)),
this.createPing(au.getPortIdOfSender(action)),
{value: 0}, // Default value
action.data,
{action: "activity_stream_undesired_event"}
);
}

async createPerformanceEvent(action) {
createPerformanceEvent(action) {
return Object.assign(
await this.createPing(),
this.createPing(),
action.data,
{action: "activity_stream_performance_event"}
);
}

async createSessionEndEvent(session) {
createSessionEndEvent(session) {
return Object.assign(
await this.createPing(),
this.createPing(),
{
session_id: session.session_id,
page: session.page,
Expand All @@ -238,8 +227,8 @@ this.TelemetryFeed = class TelemetryFeed {
);
}

async sendEvent(eventPromise) {
this.pingCentre.sendPing(await eventPromise);
async sendEvent(event_object) {
this.pingCentre.sendPing(event_object);
}

onAction(action) {
Expand Down
3 changes: 2 additions & 1 deletion system-addon/test/schemas/pings.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ const Joi = require("joi-browser");
const {MAIN_MESSAGE_TYPE, CONTENT_MESSAGE_TYPE} = require("common/Actions.jsm");

const baseKeys = {
client_id: Joi.string().required(),
// client_id will be set by PingCentre if it doesn't exist.
client_id: Joi.string().optional(),
addon_version: Joi.string().required(),
locale: Joi.string().required(),
session_id: Joi.string(),
Expand Down
Loading

0 comments on commit 118d233

Please sign in to comment.