UNPKG

@splitsoftware/splitio-commons

Version:
92 lines (91 loc) 5.11 kB
import { objectAssign } from '../utils/lang/objectAssign'; import { thenable } from '../utils/promise/thenable'; import { IMPRESSIONS_TRACKER_SUCCESS, ERROR_IMPRESSIONS_TRACKER, ERROR_IMPRESSIONS_LISTENER } from '../logger/constants'; import { CONSENT_DECLINED, DEBUG, DEDUPED, OPTIMIZED, QUEUED } from '../utils/constants'; import { strategyDebugFactory } from './strategy/strategyDebug'; import { strategyNoneFactory } from './strategy/strategyNone'; import { strategyOptimizedFactory } from './strategy/strategyOptimized'; import { uniqueKeysTrackerFactory } from './uniqueKeysTracker'; /** * Impressions tracker stores impressions in cache and pass them to the listener and integrations manager if provided. */ export function impressionsTrackerFactory(params, storage, integrationsManager) { var settings = params.settings, impressionsObserverFactory = params.impressionsObserverFactory, filterAdapterFactory = params.filterAdapterFactory; var log = settings.log, impressionListener = settings.impressionListener, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname, version = settings.version, impressionsMode = settings.sync.impressionsMode; var observer = impressionsObserverFactory(); var uniqueKeysTracker = uniqueKeysTrackerFactory(log, storage.uniqueKeys, filterAdapterFactory && filterAdapterFactory()); var noneStrategy = strategyNoneFactory(storage.impressionCounts, uniqueKeysTracker); var strategy = impressionsMode === OPTIMIZED ? strategyOptimizedFactory(observer, storage.impressionCounts) : impressionsMode === DEBUG ? strategyDebugFactory(observer) : noneStrategy; return { start: function () { uniqueKeysTracker.start(); }, stop: function () { uniqueKeysTracker.stop(); }, track: function (impressions, attributes) { if (settings.userConsent === CONSENT_DECLINED) return; var impressionsToStore = impressions.filter(function (_a) { var imp = _a.imp, disabled = _a.disabled; return disabled ? noneStrategy.process(imp) : strategy.process(imp); }); var impressionsLength = impressions.length; var impressionsToStoreLength = impressionsToStore.length; if (impressionsToStoreLength) { var res = storage.impressions.track(impressionsToStore.map(function (item) { return item.imp; })); // If we're on an async storage, handle error and log it. if (thenable(res)) { res.then(function () { log.info(IMPRESSIONS_TRACKER_SUCCESS, [impressionsLength]); }).catch(function (err) { log.error(ERROR_IMPRESSIONS_TRACKER, [impressionsLength, err]); }); } else { // Record when impressionsCache is sync only (standalone mode) // @TODO we are not dropping impressions on full queue yet, so DROPPED stats are not recorded if (storage.telemetry) { storage.telemetry.recordImpressionStats(QUEUED, impressionsToStoreLength); storage.telemetry.recordImpressionStats(DEDUPED, impressionsLength - impressionsToStoreLength); } } } // @TODO next block might be handled by the integration manager. In that case, the metadata object doesn't need to be passed in the constructor if (impressionListener || integrationsManager) { var _loop_1 = function (i) { var impressionData = { // copy of impression, to avoid unexpected behavior if modified by integrations or impressionListener impression: objectAssign({}, impressions[i].imp), attributes: attributes, ip: ip, hostname: hostname, sdkLanguageVersion: version }; // Wrap in a timeout because we don't want it to be blocking. setTimeout(function () { // integrationsManager.handleImpression does not throw errors if (integrationsManager) integrationsManager.handleImpression(impressionData); try { // @ts-ignore. An exception on the listeners should not break the SDK. if (impressionListener) impressionListener.logImpression(impressionData); } catch (err) { log.error(ERROR_IMPRESSIONS_LISTENER, [err]); } }); }; for (var i = 0; i < impressionsLength; i++) { _loop_1(i); } } } }; }