Skip to content

Commit

Permalink
Merge pull request #7 from datainsider-co/upgrade_tracking
Browse files Browse the repository at this point in the history
Upgrade tracking to 0.8.8
  • Loading branch information
tvc12 authored Jan 17, 2023
2 parents be5b652 + 985b1da commit 44f7585
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 251 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ yarn add di-web-analytics
🔥 using CDN
```html
<script>
(function(a,b,c,d,e){var f={},g=[],h=function(m){return function(){var n={};n['funcName']=m,n['arguments']=arguments,g['push'](n);};},i=['init','setLoggerLevel','autoTrackDom','enterScreenStart','enterScreen','exitScreen','setGlobalConfig','time','track','identify','setUserProfile','viewProduct','search','register','login','logout','destroySession','addToCart','removeFromCart','trackCheckoutProducts','checkout','cancelOrder','returnOrder','notifyUsingCookies','reset'];for(var j=0x0;j<i['length'];j++){f[i[j]]=h(i[j]);}var k=b['createElement'](c),l=b['getElementsByTagName'](c)[0x0];k['async']=0x1,k['src']=d,l['parentNode']['insertBefore'](k,l),a['createDiAnalytics']=function(){return e=arguments,f;},k['onload']=function(){e&&(a['DiAnalytics']['init']['apply'](a['DiAnalytics'],e),g['forEach'](function(m){m['funcName']&&a['DiAnalytics'][m['funcName']]['apply'](a['DiAnalytics'],m['arguments']);}),a['diQueue']=[]);};}(window,document,'script','https://analytics.datainsider.co/static/js/di-web-analytics/0.8.5/index.js'));
(function(a,b,c,d,e){var f={},g=[],h=function(m){return function(){var n={};n['funcName']=m,n['arguments']=arguments,g['push'](n);};},i=['init','setLoggerLevel','autoTrackDom','enterScreenStart','enterScreen','exitScreen','setGlobalConfig','time','track','identify','setUserProfile','viewProduct','search','register','login','logout','destroySession','addToCart','removeFromCart','trackCheckoutProducts','checkout','cancelOrder','returnOrder','notifyUsingCookies','reset'];for(var j=0x0;j<i['length'];j++){f[i[j]]=h(i[j]);}var k=b['createElement'](c),l=b['getElementsByTagName'](c)[0x0];k['async']=0x1,k['src']=d,l['parentNode']['insertBefore'](k,l),a['createDiAnalytics']=function(){return e=arguments,f;},k['onload']=function(){e&&(a['DiAnalytics']['init']['apply'](a['DiAnalytics'],e),g['forEach'](function(m){m['funcName']&&a['DiAnalytics'][m['funcName']]['apply'](a['DiAnalytics'],m['arguments']);}),a['diQueue']=[]);};}(window,document,'script','https://analytics.datainsider.co/static/js/di-web-analytics/0.8.8/index.js'));
window.DiAnalytics = window.createDiAnalytics(
'YOUR_API_HOST',
'YOUR_API_KEY',
{
host: 'YOUR_API_HOST',
apiKey: 'YOUR_API_KEY',
}
);
</script>
```
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "di-web-analytics",
"version": "0.8.6",
"version": "0.8.8",
"description": "Data insider web analytics",
"repository": {
"type": "git",
Expand Down
8 changes: 5 additions & 3 deletions src/init_tracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@
window,
document,
'script',
'https://analytics.datainsider.co/static/js/di-web-analytics/0.8.4/index.js'
'https://analytics.datainsider.co/static/js/di-web-analytics/0.8.7/index.js'
);

window.DiAnalytics = window.createDiAnalytics(
'https://host-api/',
'api-key',
{
host: 'https://host-api/',
apiKey: 'api-key',
}
);
2 changes: 1 addition & 1 deletion src/misc/data_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class DataManager {
localStorage.removeItem(DataManager.GLOBAL_PROPERTIES);
}

static setUserId(userId: string): void {
static setCustomerId(userId: string): void {
localStorage.setItem(DataManager.USER_ID, userId);
}

Expand Down
105 changes: 54 additions & 51 deletions src/misc/persistent_queue.ts
Original file line number Diff line number Diff line change
@@ -1,92 +1,97 @@
import Queue from 'storage-based-queue';
import {Message, SubmitEventWorker} from './workers';
import {Mutex} from 'async-mutex';
import {Event, Properties} from '../domain';
import {Logger} from '../service/logger';
import {DataManager} from './data_manager';

Queue.workers({SubmitEventWorker});

export class PersistentQueue {
private readonly queue = new Queue({
storage: 'indexeddb',
timeout: 500,
debug: false
});
export enum StorageType {
LocalStorage = 'localStorage',
IndexedDB = 'indexeddb',
InMemory = 'inmemory',
}

export abstract class PersistentQueue {
abstract start(): void;

private readonly maxSize: number;
abstract stop(): void;

abstract add(event: string, properties: Properties): void
}

export class PersistentQueueImpl extends PersistentQueue {
private readonly bufferSize: number;
private readonly flushInterval: number;
private readonly eventChannel = this.queue.create('event-track-channel');
private readonly mutex = new Mutex();
private events: Event[] = [];
private readonly eventChannel: any;
private bufferEvents: Event[] = [];
private currentScheduleId: number | null = null;

/**
* @param queueSize max size để chờ persist xuống storage
* @param flushInterval thời gian max để chờ persist, tính theo millis
* @param storageType is the storage type to use for the queue
* @param bufferSize max size để chờ persist xuống storage
* @param flushIntervalMs thời gian max để chờ persist, tính theo millis
*/
constructor(queueSize = 100, flushInterval = 60000) {
Logger.info("init PersistentQueue", {queueSize, flushInterval});
this.maxSize = queueSize;
this.flushInterval = flushInterval;

this.start();
constructor(storageType = StorageType.LocalStorage, bufferSize = 50, flushIntervalMs = 5000) {
super();
Logger.debug('init PersistentQueue', {queueSize: bufferSize, flushInterval: flushIntervalMs});
this.bufferSize = bufferSize;
this.flushInterval = flushIntervalMs;
this.eventChannel = new Queue({
storage: storageType,
timeout: 100,
debug: false
}).create('event-track-channel');
}

private start() {
start() {
Logger.debug('PersistentQueue::start');
this.eventChannel.start();
this.loadTempEvents();
Logger.debug('PersistentQueue::start completed');
}

private async loadTempEvents(): Promise<void> {
private loadTempEvents(): void {
try {
const events: Event[] = DataManager.getTemporaryEvents();
if (events.length > 0) {
await this.persist(events);
DataManager.deleteTemporaryEvents()
this.persist(events);
DataManager.deleteTemporaryEvents();
}
} catch (ex) {
Logger.error('loadTempEvents error', ex);
}

}

async stop() {
stop() {
try {
DataManager.saveTemporaryEvents(this.events);
DataManager.saveTemporaryEvents(this.bufferEvents);
this.eventChannel.stop();
} catch (ex){
} catch (ex) {
Logger.error('PersistentQueue::stop error', ex);
}
}

async add(event: string, properties: Properties): Promise<void> {
const releaser = await this.mutex.acquire();
try {
this.events.push({
name: event,
properties: properties
});

if (this.events.length > this.maxSize) {
const events = Array.from(this.events);
this.events = [];
this.persist(events);
} else {
this.schedulePersist();
}
add(event: string, properties: Properties): void {
this.bufferEvents.push({
name: event,
properties: properties
});

} finally {
releaser();
if (this.bufferEvents.length > this.bufferSize) {
const events = Array.from(this.bufferEvents);
this.bufferEvents = [];
this.persist(events);
} else {
this.schedulePersist();
}
}

private async persist(events: Event[]): Promise<void> {
private persist(events: Event[]): void {
try {
if (events.length > 0) {
await this.eventChannel.add({
this.eventChannel.add({
priority: 1,
label: 'persist-event',
createdAt: Date.now(),
Expand All @@ -105,17 +110,15 @@ export class PersistentQueue {
if (this.currentScheduleId) {
clearTimeout(this.currentScheduleId);
}

// add new schedule
this.currentScheduleId = setTimeout(async () => {
const releaser = await this.mutex.acquire();
try {
// quick swap events
const events = Array.from(this.events);
this.events = [];
const events = Array.from(this.bufferEvents);
this.bufferEvents = [];
this.persist(events);
} finally {
releaser();
} catch (ex) {
Logger.error('schedulePersist error', ex);
}
}, this.flushInterval);
}
Expand Down
36 changes: 20 additions & 16 deletions src/misc/tracking_session_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,32 @@ export class TrackingSessionManager {
}

static deleteSession() {
const session = this.getSession();
if (session && session.sessionId) {
const session: TrackingSessionInfo | undefined = this.getSession();
if (session && session?.sessionId) {
sessionStorage.removeItem(this.buildSessionStorageKey(session.sessionId));
}
localStorage.removeItem(TrackingSessionManager.SESSION_KEY);
}

static getSession(): TrackingSessionInfo {
const dataAsJSON = localStorage.getItem(TrackingSessionManager.SESSION_KEY)
let sessionInfo: TrackingSessionInfo | undefined;
if (dataAsJSON) {
sessionInfo = JSON.parse(dataAsJSON) as TrackingSessionInfo;
static getSession(): TrackingSessionInfo | undefined {
try {
const dataAsJSON = localStorage.getItem(TrackingSessionManager.SESSION_KEY)
if (dataAsJSON) {
const trackingInfo = JSON.parse(dataAsJSON) as TrackingSessionInfo;
return {
sessionId: trackingInfo.sessionId,
isExpired: this.isExpired(trackingInfo),
createdAt: trackingInfo.createdAt || 0,
expiredAt: trackingInfo.expiredAt || 0,
lastActivityAt: trackingInfo.lastActivityAt || 0,
properties: trackingInfo.properties || {}
}
} else {
return void 0;
}
} catch (ex) {
return void 0;
}

return {
sessionId: sessionInfo?.sessionId,
isExpired: this.isExpired(sessionInfo),
createdAt: sessionInfo?.createdAt || 0,
expiredAt: sessionInfo?.expiredAt || 0,
lastActivityAt: sessionInfo?.lastActivityAt || 0,
properties: sessionInfo?.properties || {}
} as TrackingSessionInfo;
}

private static isExpired(sessionInfo: TrackingSessionInfo | undefined): boolean {
Expand Down
3 changes: 2 additions & 1 deletion src/misc/workers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {Event} from '../domain';
import TRACKING_SERVICE from '../service/tracking_service';
import {Logger} from '../service';

export interface Message {
events: Event[];
Expand All @@ -13,7 +14,7 @@ export class SubmitEventWorker {
await TRACKING_SERVICE.multiTrack(events);
} catch (ex) {
// ignore tracking
console.error('track event error cause', ex);
Logger.error('track event error cause', ex);
}
}
}
12 changes: 6 additions & 6 deletions src/service/analytics_core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ export abstract class AnalyticsCore {

abstract enterScreenStart(name: string): void

abstract enterScreen(name: string, userProps?: EventProperties): Promise<void>
abstract enterScreen(name: string, userProps?: EventProperties): void

abstract exitScreen(name: string, userProps?: EventProperties): Promise<void>
abstract exitScreen(name: string, userProps?: EventProperties): void

abstract touchSession(): Promise<void>
abstract touchSession(): void

abstract time(event: string): void

abstract identify(customerId: string): void

abstract setUserProfile(customerId: string, properties: CustomerProperties): Promise<void>
abstract setUserProfile(customerId: string, properties: CustomerProperties): void

abstract track(event: string, properties: Properties | EventProperties): Promise<void>
abstract track(event: string, properties: Properties | EventProperties): void

/**
* end current session
*/
abstract destroySession(): Promise<void>;
abstract destroySession(): void;
}
Loading

0 comments on commit 44f7585

Please sign in to comment.