Skip to content

Commit 5236fe8

Browse files
authored
[SDK-686] idtype and request t (#39)
* tests, id type and request t added * changelog entry * linting * more linting * some timing issue fix * update * wording changes * changelog and split up the init id assign functions * some comments * ID type ifs * tests, comments and linting * timing for tests
1 parent ae24421 commit 5236fe8

File tree

6 files changed

+445
-44
lines changed

6 files changed

+445
-44
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 22.02.0
2+
- !! Major breaking change !! Device ID provided during the init will be ignored if a device ID was provided previously
3+
- Added a new init time flag which erases the previously stored device ID. This allows to set new device ID during init
4+
- Added a call to get the device ID type of the user
5+
- Added a call to get the device ID of the user
6+
- Now it appends the device ID type with each request
7+
18
## 21.11.0
29
- !! Major breaking change !! Changing device ID without merging will now clear the current consent. Consent has to be given again after performing this action.
310
- ! Minor breaking change ! Multiple values now have a default limit adjustable at initialization:

lib/countly-common.js

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,38 @@ var cc = {
88
debugBulk: false,
99
debugBulkUser: false,
1010
/**
11-
*
12-
*log level Enums:
13-
*Error - this is a issues that needs attention right now.
14-
*Warning - this is something that is potentially a issue. Maybe a deprecated usage of something, maybe consent is enabled but consent is not given.
15-
*Info - All publicly exposed functions should log a call at this level to indicate that they were called. These calls should include the function name.
16-
*Debug - this should contain logs from the internal workings of the SDK and it's important calls. This should include things like the SDK configuration options, success or fail of the current network request, "request queue is full" and the oldest request get's dropped, etc.
17-
*Verbose - this should give a even deeper look into the SDK's inner working and should contain things that are more noisy and happen often.
18-
*/
11+
* log level Enums:
12+
* Error - this is a issues that needs attention right now.
13+
* Warning - this is something that is potentially a issue. Maybe a deprecated usage of something, maybe consent is enabled but consent is not given.
14+
* Info - All publicly exposed functions should log a call at this level to indicate that they were called. These calls should include the function name.
15+
* Debug - this should contain logs from the internal workings of the SDK and it's important calls. This should include things like the SDK configuration options, success or fail of the current network request, "request queue is full" and the oldest request get's dropped, etc.
16+
* Verbose - this should give a even deeper look into the SDK's inner working and should contain things that are more noisy and happen often.
17+
*/
1918
logLevelEnums: {
2019
ERROR: '[ERROR] ',
2120
WARNING: '[WARNING] ',
2221
INFO: '[INFO] ',
2322
DEBUG: '[DEBUG] ',
2423
VERBOSE: '[VERBOSE] ',
2524
},
25+
/**
26+
* device ID type:
27+
* 0 - device ID was set by the developer during init
28+
* 1 - device ID was auto generated by Countly
29+
*/
30+
deviceIdTypeEnums: {
31+
DEVELOPER_SUPPLIED: 0,
32+
SDK_GENERATED: 1,
33+
},
2634
/**
2735
* At the current moment there are following internal events and their respective required consent:
28-
[CLY]_nps - "feedback" consent
29-
[CLY]_survey - "feedback" consent
30-
[CLY]_star_rating - "star_rating" consent
31-
[CLY]_view - "view" consent
32-
[CLY]_orientation - "users" consent
33-
[CLY]_push_action - "push" consent
34-
[CLY]_action - "clicks" or "scroll" consent
36+
* [CLY]_nps - "feedback" consent
37+
* [CLY]_survey - "feedback" consent
38+
* [CLY]_star_rating - "star_rating" consent
39+
* [CLY]_view - "view" consent
40+
* [CLY]_orientation - "users" consent
41+
* [CLY]_push_action - "push" consent
42+
* [CLY]_action - "clicks" or "scroll" consent
3543
*/
3644
internalEventKeyEnums: {
3745
NPS: '[CLY]_nps',
@@ -106,11 +114,11 @@ var cc = {
106114
return newStr;
107115
},
108116
/**
109-
* Retrieve only specific properties from object
110-
* @param {Object} orig - object from which to get properties
111-
* @param {Array} props - list of properties to get
112-
* @returns {Object} Object with requested properties
113-
*/
117+
* Retrieve only specific properties from object
118+
* @param {Object} orig - object from which to get properties
119+
* @param {Array} props - list of properties to get
120+
* @returns {Object} Object with requested properties
121+
*/
114122
getProperties: function getProperties(orig, props) {
115123
var ob = {};
116124
var prop;
@@ -123,21 +131,21 @@ var cc = {
123131
return ob;
124132
},
125133
/**
126-
* Removing trailing slashes
127-
* @memberof Countly._internals
128-
* @param {String} str - string from which to remove traling slash
129-
* @returns {String} modified string
130-
*/
134+
* Removing trailing slashes
135+
* @memberof Countly._internals
136+
* @param {String} str - string from which to remove traling slash
137+
* @returns {String} modified string
138+
*/
131139
stripTrailingSlash: function stripTrailingSlash(str) {
132140
if (str.substring(str.length - 1) === "/") {
133141
return str.substring(0, str.length - 1);
134142
}
135143
return str;
136144
},
137145
/**
138-
* Generate random UUID value
139-
* @returns {String} random UUID value
140-
*/
146+
* Generate random UUID value
147+
* @returns {String} random UUID value
148+
*/
141149
generateUUID: function generateUUID() {
142150
var d = new Date().getTime();
143151
var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
@@ -148,7 +156,15 @@ var cc = {
148156
return uuid;
149157
},
150158
/**
151-
* Log data if debug mode is enabled
159+
* Check if value is in UUID format
160+
* @param {string} providedId - Id to check
161+
* @returns {Boolean} true if it is in UUID format
162+
*/
163+
isUUID: function isUUID(providedId) {
164+
return /[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-4[0-9a-fA-F]{3}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/.test(providedId);
165+
},
166+
/**
167+
* Log data if debug mode is enabled
152168
* @param {string} level - log level (error, warning, info, debug, verbose)
153169
* @param {string} message - any string message
154170
*/

lib/countly.js

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ Countly.Bulk = Bulk;
7272
var maxStackTraceLinesPerThread = 30;
7373
var maxStackTraceLineLength = 200;
7474
var __data = {};
75+
var deviceIdType = null;
7576

7677
/**
7778
* Array with list of available features that you can require consent for
@@ -101,6 +102,8 @@ Countly.Bulk = Bulk;
101102
* @param {number} [conf.session_update=60] - how often in seconds should session be extended
102103
* @param {number} [conf.max_events=100] - maximum amount of events to send in one batch
103104
* @param {boolean} [conf.force_post=false] - force using post method for all requests
105+
* @param {boolean} [conf.clear_stored_device_id=false] - set it to true if you want to erase the stored device ID
106+
* @param {boolean} [conf.test_mode=false] - set it to true if you want to initiate test_mode
104107
* @param {string} [conf.storage_path="../data/"] - where SDK would store data, including id, queues, etc
105108
* @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
106109
* @param {boolean|function} [conf.remote_config=false] - Enable automatic remote config fetching, provide callback function to be notified when fetching done
@@ -147,6 +150,8 @@ Countly.Bulk = Bulk;
147150
maxEventBatch = conf.max_events || Countly.max_events || maxEventBatch;
148151
metrics = conf.metrics || Countly.metrics || {};
149152
conf.debug = conf.debug || Countly.debug || false;
153+
conf.clear_stored_device_id = conf.clear_stored_device_id || false;
154+
Countly.test_mode = conf.test_mode || false;
150155
Countly.app_key = conf.app_key || Countly.app_key || null;
151156
Countly.url = cc.stripTrailingSlash(conf.url || Countly.url || "");
152157
Countly.app_version = conf.app_version || Countly.app_version || "0.0";
@@ -179,15 +184,53 @@ Countly.Bulk = Bulk;
179184
// eslint-disable-next-line no-console
180185
console.log(ex.stack);
181186
}
187+
// clear stored device ID if flag is set
188+
if (conf.clear_stored_device_id) {
189+
cc.log(cc.logLevelEnums.WARNING, "Erasing stored ID");
190+
storeSet("cly_id", null);
191+
storeSet("cly_id_type", null);
192+
}
182193

183194
if (Countly.url === "") {
184195
cc.log(cc.logLevelEnums.ERROR, "Please provide server URL");
185196
}
186197
else {
187198
cc.log(cc.logLevelEnums.INFO, "Countly initialized");
188199
if (cluster.isMaster) {
189-
Countly.device_id = conf.device_id || Countly.device_id || getId();
200+
// fetch stored ID and ID type
201+
var storedId = storeGet("cly_id", null);
202+
var storedIdType = storeGet("cly_id_type", null);
203+
// if there was a stored ID
204+
if (storedId !== null) {
205+
Countly.device_id = storedId;
206+
// deviceIdType = storedIdType || cc.deviceIdTypeEnums.DEVELOPER_SUPPLIED;
207+
if (storedIdType === null) {
208+
// even though the device ID set, not type was set, setting it here
209+
if (cc.isUUID(storedId)) {
210+
// assuming it is a UUID so also assuming it is SDK generated
211+
storedIdType = cc.deviceIdTypeEnums.SDK_GENERATED;
212+
}
213+
else {
214+
// assuming it was set by the developer
215+
storedIdType = cc.deviceIdTypeEnums.DEVELOPER_SUPPLIED;
216+
}
217+
}
218+
deviceIdType = storedIdType;
219+
}
220+
// if the user provided device ID during the init and no ID was stored
221+
else if (conf.device_id || Countly.device_id) {
222+
Countly.device_id = conf.device_id || Countly.device_id;
223+
deviceIdType = cc.deviceIdTypeEnums.DEVELOPER_SUPPLIED;
224+
}
225+
// if no device ID provided during init nor it was stored previously
226+
else {
227+
Countly.device_id = cc.generateUUID();
228+
deviceIdType = cc.deviceIdTypeEnums.SDK_GENERATED;
229+
}
230+
// save the ID and ID type
190231
storeSet("cly_id", Countly.device_id);
232+
storeSet("cly_id_type", deviceIdType);
233+
// create queues
191234
requestQueue = storeGet("cly_queue", []);
192235
eventQueue = storeGet("cly_event", []);
193236
remoteConfigs = storeGet("cly_remote_configs", {});
@@ -251,6 +294,7 @@ Countly.Bulk = Bulk;
251294
maxStackTraceLinesPerThread = 30;
252295
maxStackTraceLineLength = 200;
253296
__data = {};
297+
deviceIdType = null;
254298

255299
// cc DEBUG
256300
cc.debug = false;
@@ -539,6 +583,24 @@ Countly.Bulk = Bulk;
539583
}
540584
};
541585

586+
/**
587+
* Check and return the current device id type
588+
* @returns {number} a number that indicates the device id type
589+
*/
590+
Countly.get_device_id_type = function() {
591+
cc.log(cc.logLevelEnums.INFO, `check_device_id_type, Retrieving the current device id type.[${deviceIdType}]`);
592+
return deviceIdType;
593+
};
594+
595+
/**
596+
* Gets the current device id
597+
* @returns {string} device id
598+
*/
599+
Countly.get_device_id = function() {
600+
cc.log(cc.logLevelEnums.INFO, `get_device_id, Retrieving the device id: [${Countly.device_id}]`);
601+
return Countly.device_id;
602+
};
603+
542604
/**
543605
* Change current user/device id
544606
* @param {string} newId - new user/device ID to use
@@ -564,7 +626,9 @@ Countly.Bulk = Bulk;
564626
}
565627
var oldId = Countly.device_id;
566628
Countly.device_id = newId;
629+
deviceIdType = cc.deviceIdTypeEnums.DEVELOPER_SUPPLIED;
567630
storeSet("cly_id", Countly.device_id);
631+
storeSet("cly_id_type", deviceIdType);
568632
cc.log(cc.logLevelEnums.INFO, "change_id, Changing ID");
569633
if (merge) {
570634
if (Countly.check_any_consent()) {
@@ -1297,6 +1361,7 @@ Countly.Bulk = Bulk;
12971361
request.device_id = Countly.device_id;
12981362
request.sdk_name = SDK_NAME;
12991363
request.sdk_version = SDK_VERSION;
1364+
request.t = deviceIdType;
13001365
if (Countly.check_consent("location")) {
13011366
if (Countly.country_code) {
13021367
request.country_code = Countly.country_code;
@@ -1369,7 +1434,7 @@ Countly.Bulk = Bulk;
13691434
}
13701435

13711436
// process request queue with event queue
1372-
if (requestQueue.length > 0 && readyToProcess && cc.getTimestamp() > failTimeout) {
1437+
if (requestQueue.length > 0 && readyToProcess && cc.getTimestamp() > failTimeout && !Countly.test_mode) {
13731438
readyToProcess = false;
13741439
var params = requestQueue.shift();
13751440
cc.log(cc.logLevelEnums.DEBUG, "Processing request", params);
@@ -1388,14 +1453,6 @@ Countly.Bulk = Bulk;
13881453
setTimeout(heartBeat, beatInterval);
13891454
}
13901455

1391-
/**
1392-
* Get device ID, stored one, or generate new one
1393-
* @returns {String} device id
1394-
*/
1395-
function getId() {
1396-
return storeGet("cly_id", null) || cc.generateUUID();
1397-
}
1398-
13991456
/**
14001457
* Get metrics of the browser or config object
14011458
* @returns {Object} Metrics object

test/helpers/helper_functions.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,22 @@ function readRequestQueue() {
2525
}
2626

2727
// queue files clearing logic
28-
function clearStorage() {
28+
function clearStorage(keepID) {
29+
keepID = keepID || false;
2930
// Resets Countly
3031
Countly.halt(true);
3132
// clean storages
32-
if (fs.existsSync(idDir)) {
33-
fs.unlinkSync(idDir);
34-
}
3533
if (fs.existsSync(eventDir)) {
3634
fs.unlinkSync(eventDir);
3735
}
3836
if (fs.existsSync(reqDir)) {
3937
fs.unlinkSync(reqDir);
4038
}
39+
if (!keepID) {
40+
if (fs.existsSync(idDir)) {
41+
fs.unlinkSync(idDir);
42+
}
43+
}
4144
}
4245
/**
4346
* bunch of tests specifically gathered for testing events

0 commit comments

Comments
 (0)