Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rc api final #287

Merged
merged 17 commits into from
Sep 27, 2022
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
- ! Minor breaking change ! If no domain whitelist is provided for the heatmaps the SDK will fallback to your server url
- Fixed a bug where heatmap files were susceptible to DOM XSS
- Users can now input their domain whitelist for heatmaps feature during init
- Implementing new Remote Config/AB testing API:
- Added an init time flag to enable/disable new remote config API (default: disabled)
- Added a new call to opt in users to the A/B testing for the given keys
- Added an init time flag to enable/disable automatically opting in users for A/B testing while fetching remote config (with new RC API)(default: enabled)

## 22.06.1
- Added SDK calls to report Feedback widgets manually
Expand Down
14 changes: 11 additions & 3 deletions examples/example_remote_config.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
app_key: "YOUR_APP_KEY",
url: "https://try.count.ly", //your server goes here
debug: true,
rc_automatic_optin_for_ab: true, // set it to false for not opting in users for AB testing while fetching the remote config (only with latest API)
use_explicit_rc_api: false, // set it to true to use the latest API
remote_config: function (err, configs) {
//handle initial remote configs here
console.log(err, configs);
Expand All @@ -31,19 +33,25 @@ <h1>Remote Config</h1>
<center>
<img src="./images/team_countly.jpg" id="wallpaper" />
<br />
<input type="button" onclick="reloadConfig()" value="Reload Config">
<input type="button" onclick="fetchConfig()" value="Fetch Config">
<input type="button" onclick="getConfig()" value="Get Config">
<input type="button" onclick="getConfig('test')" value="Get config for key Test">
<input type="button" onclick="ab(['key1','key2'])" value="Enroll user to AB test">
<p><a href='http://count.ly/'>Count.ly</a></p>
</center>
<script type='text/javascript'>
//reload configs
function reloadConfig(ob) {
// fetches all keys
function fetchConfig() {
Countly.fetch_remote_config(function (err, config) {
alert(JSON.stringify(config));
});
}

// enroll user
function ab(keyArray) {
Countly.enrollUserToAb(keyArray);
}

//get config
function getConfig(key) {
alert(JSON.stringify(Countly.get_remote_config(key)));
Expand Down
64 changes: 45 additions & 19 deletions lib/countly.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@
this.onload = getConfig("onload", ob, []);
this.utm = getConfig("utm", ob, { source: true, medium: true, campaign: true, term: true, content: true });
this.ignore_prefetch = getConfig("ignore_prefetch", ob, true);
this.rcAutoOptinAb = getConfig("rc_automatic_optin_for_ab", ob, true);
this.useExplicitRcApi = getConfig("use_explicit_rc_api", ob, false);
this.debug = getConfig("debug", ob, false);
this.test_mode = getConfig("test_mode", ob, false);
this.metrics = getConfig("metrics", ob, {});
Expand Down Expand Up @@ -292,6 +294,11 @@
lsSupport = false;
}

if (!this.rcAutoOptinAb && !this.useExplicitRcApi) {
log(logLevelEnums.WARNING, "initialize, Auto opting is disabled, switching to explicit RC API");
this.useExplicitRcApi = true;
}

if (!Array.isArray(ignoreReferrers)) {
ignoreReferrers = [];
}
Expand Down Expand Up @@ -426,6 +433,12 @@
if (this.remote_config) {
log(logLevelEnums.DEBUG, "initialize, remote_config callback provided:[" + !!this.remote_config + "]");
}
if (typeof this.rcAutoOptinAb === "boolean") {
log(logLevelEnums.DEBUG, "initialize, automatic RC optin is enabled:[" + this.rcAutoOptinAb + "]");
}
if (!this.useExplicitRcApi) {
log(logLevelEnums.WARNING, "initialize, will use legacy RC API. Consider enabling new API during init with use_explicit_rc_api flag");
}
if (this.track_domains) {
log(logLevelEnums.DEBUG, "initialize, tracking domain info:[" + this.track_domains + "]");
}
Expand Down Expand Up @@ -693,6 +706,8 @@
self.ip_address = undefined;
self.ignore_bots = undefined;
self.force_post = undefined;
self.rcAutoOptinAb = undefined;
self.useExplicitRcApi = undefined;
self.remote_config = undefined;
self.ignore_visitor = undefined;
self.require_consent = undefined;
Expand Down Expand Up @@ -1609,8 +1624,17 @@
* @param {function=} callback - Callback to notify with first param error and second param remote config object
* */
this.fetch_remote_config = function(keys, omit_keys, callback) {
log(logLevelEnums.INFO, "fetch_remote_config, Fetching remote config");
fetch_remote_config_v2(keys, omit_keys, 1, "legacy", callback);
// use new RC API
if (this.useExplicitRcApi) {
log(logLevelEnums.INFO, "fetch_remote_config, Fetching remote config");
// opt in is true(1) or false(0)
var opt = this.rcAutoOptinAb ? 1 : 0;
fetch_remote_config_explicit(keys, omit_keys, opt, callback);
return;
}

log(logLevelEnums.WARNING, "fetch_remote_config, Fetching remote config, with legacy API");
fetch_remote_config_explicit(keys, omit_keys, "legacy", callback);
};

/**
Expand All @@ -1621,8 +1645,8 @@
* @param {string=} api - which API to use, if not provided would use default ("legacy" is for method="fetch_remote_config", default is method="rc")
* @param {function=} callback - Callback to notify with first param error and second param remote config object
* */
function fetch_remote_config_v2(keys, omit_keys, optIn, api, callback) {
log(logLevelEnums.INFO, "fetch_remote_config_v2, Fetching remote config");
function fetch_remote_config_explicit(keys, omit_keys, optIn, api, callback) {
log(logLevelEnums.INFO, "fetch_remote_config_explicit, Fetching sequence initiated");
var request = {
method: "rc"
};
Expand Down Expand Up @@ -1653,14 +1677,14 @@
provivedCall = arguments[j];
}
}
if (this.check_consent(featureEnums.SESSIONS)) {
if (self.check_consent(featureEnums.SESSIONS)) {
request.metrics = JSON.stringify(getMetrics());
}
if (this.check_consent(featureEnums.REMOTE_CONFIG)) {
if (self.check_consent(featureEnums.REMOTE_CONFIG)) {
prepareRequest(request);
sendXmlHttpRequest("fetch_remote_config_v2", this.url + readPath, request, function(err, params, responseText) {
sendXmlHttpRequest("fetch_remote_config_explicit", self.url + readPath, request, function(err, params, responseText) {
if (err) {
log(logLevelEnums.ERROR, "fetch_remote_config_v2, An error occurred: " + err);
log(logLevelEnums.ERROR, "fetch_remote_config_explicit, An error occurred: " + err);
return;
}
try {
Expand All @@ -1678,17 +1702,17 @@
setValueInStorage("cly_remote_configs", remoteConfigs);
}
catch (ex) {
log(logLevelEnums.ERROR, "fetch_remote_config_v2, Had an issue while parsing the response: " + ex);
log(logLevelEnums.ERROR, "fetch_remote_config_explicit, Had an issue while parsing the response: " + ex);
}
if (provivedCall) {
log(logLevelEnums.INFO, "fetch_remote_config_v2, Callback function is provided");
log(logLevelEnums.INFO, "fetch_remote_config_explicit, Callback function is provided");
provivedCall(err, remoteConfigs);
}
// JSON array can pass
}, true);
}
else {
log(logLevelEnums.ERROR, "fetch_remote_config_v2, Remote config requires explicit consent");
log(logLevelEnums.ERROR, "fetch_remote_config_explicit, Remote config requires explicit consent");
if (provivedCall) {
provivedCall(new Error("Remote config requires explicit consent"), remoteConfigs);
}
Expand All @@ -1699,32 +1723,32 @@
* AB testing key provider, opts the user in for the selected keys
* @param {array=} keys - Array of keys opt in FOR
* */
function optAB(keys) {
log(logLevelEnums.INFO, "optAB, Providing AB test keys to opt in for");
this.enrollUserToAb = function(keys) {
log(logLevelEnums.INFO, "enrollUserToAb, Providing AB test keys to opt in for");
if (!keys || !Array.isArray(keys) || keys.length === 0) {
log(logLevelEnums.ERROR, "optAB, No keys provided");
log(logLevelEnums.ERROR, "enrollUserToAb, No keys provided");
return;
}
var request = {
method: "ab",
keys: JSON.stringify(keys)
};
prepareRequest(request);
sendXmlHttpRequest("optAB", this.url + readPath, request, function(err, params, responseText) {
sendXmlHttpRequest("enrollUserToAb", this.url + readPath, request, function(err, params, responseText) {
if (err) {
log(logLevelEnums.ERROR, "optAB, An error occurred: " + err);
log(logLevelEnums.ERROR, "enrollUserToAb, An error occurred: " + err);
return;
}
try {
var resp = JSON.parse(responseText);
log(logLevelEnums.DEBUG, "optAB, Parsed the response's result: [" + resp.result + "]");
log(logLevelEnums.DEBUG, "enrollUserToAb, Parsed the response's result: [" + resp.result + "]");
}
catch (ex) {
log(logLevelEnums.ERROR, "optAB, Had an issue while parsing the response: " + ex);
log(logLevelEnums.ERROR, "enrollUserToAb, Had an issue while parsing the response: " + ex);
}
// JSON array can pass
}, true);
}
};

/**
* Gets remote config object (all key/value pairs) or specific value for provided key from the storage
Expand Down Expand Up @@ -4352,6 +4376,8 @@
* @param {number} [conf.max_stack_trace_line_length=200] - maximum amount of characters are allowed per stack trace line. This limits also the crash message length
* @param {array=} conf.ignore_referrers - array with referrers to ignore
* @param {boolean} [conf.ignore_prefetch=true] - ignore prefetching and pre rendering from counting as real website visits
* @param {boolean} [conf.rc_automatic_optin_for_ab=true] - opts in the user for A/B testing while fetching the remote config (if true)
* @param {boolean} [conf.use_explicit_rc_api=false] - set it to true to use the new remote config API
* @param {boolean} [conf.force_post=false] - force using post method for all requests
* @param {boolean} [conf.ignore_visitor=false] - ignore this current visitor
* @param {boolean} [conf.require_consent=false] - Pass true if you are implementing GDPR compatible consent management. It would prevent running any functionality without proper consent
Expand Down