Skip to content

Instantly share code, notes, and snippets.

@motin
Last active April 17, 2018 12:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save motin/24713495ad4363430f3fa5735c57a7a0 to your computer and use it in GitHub Desktop.
Save motin/24713495ad4363430f3fa5735c57a7a0 to your computer and use it in GitHub Desktop.
/* global Study */
// All background/content scripts wraps their logic to wait for the study onAllowed event
// (listener needs to be setup before running Study.onWebExtensionLoad())
browser.study.onAllowed.addListener(async(variationName) => {
enableFeature(variationName);
});
// Will send the onAllow event if the study is allowed to run
Study.onWebExtensionLoad();
// The main entry-point for our study-relevant feature
function enableFeature(variationName) {
console.log(
`Enabling a feature relevant for the study, style: ${variationName}`,
);
}
const studySetup = {
// activeExperimentsTag
activeExperimentName: "demoStudy",
// uses shield|pioneer pipeline, watches those permissions
pattern: "shield",
telemetry: {
send: true, // assumed false. Actually send pings?
removeTestingFlag: false, // Marks pings as testing, set true for actual release
},
endings: {
/** standard endings */
"user-disable": {
baseUrl: "http://www.example.com/?reason=user-disable",
},
ineligible: {
baseUrl: "http://www.example.com/?reason=ineligible",
},
expired: {
baseUrl: "http://www.example.com/?reason=expired",
},
dataPermissionsRevoked: {
baseUrl: null,
study_state: "ended-neutral",
},
/** User defined endings */
"some-study-defined-ending": {
study_state: "ended-neutral",
baseUrl: null,
},
},
logLevel: 10,
/* Study branches and sample weights, overweighing feature branches */
weightedVariations: [
{
name: "feature-active",
weight: 1.5,
},
{
name: "feature-passive",
weight: 1.5,
},
{
name: "control",
weight: 1,
},
],
variationOverride: "feature-active", // optional, overrides
};
// eslint-disable-next-line no-unused-vars
this.Study = class {
static async isEligible() {
const dataPermissions = await browser.study.dataPermissions();
// Could have other reasons to be eligible, such as add-ons or whatever
return dataPermissions.shield;
}
static async onWebExtensionLoad() {
// First action - as early as possible - let the API know about our
// desired study setup and set default values where necessary
browser.study.setup(studySetup);
// Now we can send telemetry, because we have a variation
// Track installs in the wild
browser.runtime.onInstalled.addListener(browser.study.onInstalled);
// Ensure that this profile gets enrolled in the study or uninstalled
if (!browser.study.isEnrolled()) {
const eligible = await this.isEligible();
if (eligible) {
await browser.study.enroll();
} else {
await browser.study.uninstall();
}
}
// Tell our background/content scripts that our study is allowed to run
browser.study.allow();
}
};
@gregglind
Copy link

  • +1 for 'enroll'
  • In this design, it looks like the tracking for 'first run or not' is in the utils. That's fine, but will have to be stored as a pref. It's hard to debug cases of that from the addon, unless we allow override flags.
  • claim: if we are doing that 'first install ts' storage in the study, then lets make it an optional arg, just like variation, and make the method very very heavy.
  • tempting to give back A LOT as the onEnroll call.

Related to this: Bianca and I think that the 'endStudy' should message that the study should end, but not do the actual work of opening tabs / unsinstalling. This is because it's easier to do that work from the addon AND it allows the addon to interrupt, shut down, cleanup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment