From 37ed21f8e75128e7fd9f52be86c5c744f4148479 Mon Sep 17 00:00:00 2001 From: Danail Stoyanov Date: Thu, 24 Oct 2024 09:40:20 +0300 Subject: [PATCH] feat: add timestamp to session generations in o-tracking --- libraries/o-tracking/src/javascript/core.js | 1 + .../o-tracking/src/javascript/core/session.js | 40 +++++++++++++++---- libraries/o-tracking/src/javascript/utils.js | 21 ++++++++++ libraries/o-tracking/test/core.test.js | 3 +- .../o-tracking/test/core/session.test.js | 15 +++++++ 5 files changed, 71 insertions(+), 9 deletions(-) diff --git a/libraries/o-tracking/src/javascript/core.js b/libraries/o-tracking/src/javascript/core.js index 830c29d2e0..d3f7be4102 100644 --- a/libraries/o-tracking/src/javascript/core.js +++ b/libraries/o-tracking/src/javascript/core.js @@ -55,6 +55,7 @@ function track(config, callback = function(){ /* empty */}) { device: { spoor_session: currentSession.id, spoor_session_is_new: currentSession.isNew, + spoor_session_timestamp: currentSession.timestamp, spoor_id: userID(), }, }; diff --git a/libraries/o-tracking/src/javascript/core/session.js b/libraries/o-tracking/src/javascript/core/session.js index e5f8c8e27e..541574ba0d 100644 --- a/libraries/o-tracking/src/javascript/core/session.js +++ b/libraries/o-tracking/src/javascript/core/session.js @@ -1,13 +1,15 @@ -import {is, merge, isUndefined, guid} from '../utils.js'; +import {is, merge, isUndefined, guid, namedLog} from '../utils.js'; import {Store} from './store.js'; /** * @typedef {object} Session * @property {string} id - The id of the session * @property {boolean} isNew - Whether it is a brand new session + * @property {number} timestamp - The timestamp of the session generation */ let store; +const logger = namedLog('Core.Session') const defaultSessionConfig = { storage: 'best', name: 'session', @@ -20,14 +22,20 @@ const defaultSessionConfig = { * @param {string} session - The session to be stored. * @returns {void} */ -function setSession(session) { +function setSession(session, timestamp) { const d = new Date(); d.setTime(d.getTime() + store.config.expires); - store.write({ + const sessionData = { value: session, - expiry: d.valueOf() - }); + expiry: d.valueOf(), + } + if(timestamp) { + sessionData.timestamp = timestamp; + } + logger('Setting session', sessionData) + + store.write(sessionData); } /** @@ -39,16 +47,29 @@ function getSession() { const s = store.read(); let session; let isNew = false; + let sessionTimestamp; if (s) { - const d = new Date().valueOf(); + logger("Found session", s) + const currentDate = new Date(); + const d = currentDate.valueOf(); + const timestamp = currentDate.getTime(); const exp = parseInt(s.expiry, 10); // If current session is active. if (exp >= d) { session = s.value; + sessionTimestamp = s.timestamp; + + // session is active but no generated timestamp + if(!sessionTimestamp) { + logger("Session is valid but no timestamp, generating timestamp.") + sessionTimestamp = timestamp; + } } else { - // session has expired, generate a new one + // session has expired, generate a new one along with a new timestamp + logger("Session has expired, generating new one") + sessionTimestamp = timestamp; session = guid(); isNew = true; } @@ -56,15 +77,18 @@ function getSession() { // No active session, gen a new one. if (!session) { + logger("No session found, generating new one") session = guid(); + sessionTimestamp = new Date().getTime(); isNew = true; } // Refreshes the cookie... - setSession(session); + setSession(session, sessionTimestamp); return { id: session, + timestamp: sessionTimestamp, isNew: isNew }; } diff --git a/libraries/o-tracking/src/javascript/utils.js b/libraries/o-tracking/src/javascript/utils.js index 5217281a29..7c8b34fff0 100644 --- a/libraries/o-tracking/src/javascript/utils.js +++ b/libraries/o-tracking/src/javascript/utils.js @@ -27,6 +27,26 @@ function log(...args) { } } +/** + * Creates a logging function that logs messages to the console with a specified namespace. + * + * @function namedLog + * @param {string} namespace - The namespace to be prefixed to each log message. + * @returns {function} A function that logs messages to the console with the given namespace if the configuration allows. + * + * @example + * const log = namedLog('MyNamespace'); + * log('This is a message'); + * // Output: [MyNamespace]: This is a message + */ +function namedLog(namespace) { + return function(...args) { + if(get('config').test && window.console) { + window.console.log(`%c[${namespace}]:`, 'color: teal', ...args) + } + } +} + /** * Tests if variable is a certain type. Defaults to check for undefined if no type specified. * @@ -389,6 +409,7 @@ function isDeepEqual(a, b) { export { log, + namedLog, is, is as isUndefined, merge, diff --git a/libraries/o-tracking/test/core.test.js b/libraries/o-tracking/test/core.test.js index f2fb38fc41..a2f178fb0a 100644 --- a/libraries/o-tracking/test/core.test.js +++ b/libraries/o-tracking/test/core.test.js @@ -78,9 +78,10 @@ describe('Core', function () { proclaim.equal(sent_data.user.user_id, "userID"); // Device - proclaim.deepEqual(Object.keys(sent_data.device), ["spoor_session","spoor_session_is_new","spoor_id"]); + proclaim.deepEqual(Object.keys(sent_data.device), ["spoor_session","spoor_session_is_new","spoor_session_timestamp", "spoor_id"]); proclaim.equal(sent_data.device.spoor_session, session().id); proclaim.equal(sent_data.device.spoor_session_is_new, session().isNew); + proclaim.equal(sent_data.device.spoor_session_timestamp, session().timestamp); }); diff --git a/libraries/o-tracking/test/core/session.test.js b/libraries/o-tracking/test/core/session.test.js index 66c255ca4c..aff5adcee8 100644 --- a/libraries/o-tracking/test/core/session.test.js +++ b/libraries/o-tracking/test/core/session.test.js @@ -35,6 +35,7 @@ describe('Core.Session', function () { const newSession = getSession(); proclaim.equal(newSession.id, session.id); proclaim.equal(newSession.isNew, false); + proclaim.equal(newSession.timestamp, session.timestamp) }); }); @@ -59,6 +60,20 @@ describe('Core.Session', function () { proclaim.isTrue(newSession.isNew); done(); }, 2) + }); + + it('should generate timestamp for session', () => { + const currentTimestamp = new Date().getTime(); + proclaim.equal(currentTimestamp, getSession().timestamp) + }) + + it('should generate a new timestamp if session has expired', (done) => { + const prevSession = initSession({expires: 1}); + setTimeout(function() { + const newSession = getSession(); + proclaim.notEqual(prevSession.timestamp, newSession.timestamp); + done() + }, 2) }) }) });