@benshi.ai/js-sdk
Version:
Benshi SDK
182 lines (141 loc) • 4.83 kB
text/typescript
import {
Event,
EventTeaser,
} from '../core/typings'
import { getNetworkInformation, getOperatingSystem } from '../drivers/BsSystem'
import { debug } from '../logging'
import BsSender from './BsSender'
import { ContentBlock } from '../modules/Navigation/typings'
import ImpressionsDetector from './impressions'
import { ImpressionEventType } from './impressions/typings'
import { toISOLocal } from '../utils'
export default class BsCore {
private static instance: BsCore;
private deviceId: string
private searchId = ''
private sender: BsSender
private impressionDetectorClass
private impressionsDetectors: {
[key: string]: ImpressionsDetector
} = {}
private defaultBlock
private debug
private currentBlock
private user_id = ''
private constructor(
sender: BsSender,
impressionDetector,
debugging: boolean,
defaultBlock: ContentBlock,
deviceId: string
) {
this.sender = sender
this.impressionDetectorClass = impressionDetector
this.deviceId = deviceId
this.defaultBlock = defaultBlock
this.debug = debug(debugging)
}
public static createInstance(
sender: BsSender,
impressionDetectorClass,
debugging: boolean,
defaultBlock: ContentBlock,
deviceId: string) {
if (!!BsCore.instance) {
return BsCore.instance
}
BsCore.instance = new BsCore(sender, impressionDetectorClass, debugging, defaultBlock, deviceId)
return BsCore.instance
}
public static getInstance(): BsCore {
if (!BsCore.instance) {
throw new Error('bslog-instance-not-created')
}
return BsCore.instance;
}
public login(userId: string) {
this.user_id = userId
}
public logout(userId: string) {
this.user_id = userId
}
private resolveModule(module: ContentBlock): ContentBlock {
// logPageEvents are triggered automatically by the system. We do not
// know whether the web application calls setCurrentBlock before or after that:
const delta = 50;
if (module === ContentBlock.Core) {
// in this case the event could be triggered by several modules
// so the SDK must decide which one must be included in the event
// sent to server (i.e.: page or media events)
if (this.currentBlock) {
return this.currentBlock
} else {
return this.defaultBlock
}
} else {
// specific module (i.e.: triggered by the ELearning module)
return module
}
}
private resolveUserId(overWrittedUserId: string, user_id: string, device_id: string): string {
if (overWrittedUserId && overWrittedUserId.length !== 0) {
return overWrittedUserId
}
return user_id || device_id
}
public async trackEvent(
eventTeaser: EventTeaser,
moduleName: ContentBlock,
overWrittedUserId: string,
sendNow: boolean
): Promise<void> {
const event: Event = {
...eventTeaser,
block: this.resolveModule(moduleName),
ol: true,
ts: toISOLocal(new Date())
}
this.sender.add(this.resolveUserId(overWrittedUserId, this.user_id, this.deviceId), this.deviceId, event, sendNow)
}
public startTrackingImpressions(impressionHandler, containerClassname, itemClassname, searchId) {
this.impressionsDetectors[containerClassname] = new this.impressionDetectorClass({ intersectionThreshold: 0.5 })
this.impressionsDetectors[containerClassname].on(ImpressionEventType.Impression, impressionHandler)
this.impressionsDetectors[containerClassname].start(containerClassname, itemClassname, { search_id: searchId })
}
public stopTrackingImpressions(containerClassname) {
if (!containerClassname) {
Object.values(this.impressionsDetectors).forEach(detector => detector.stop())
return
}
if (!this.impressionsDetectors[containerClassname]) {
return
}
this.impressionsDetectors[containerClassname].stop()
}
public restartTrackingImpressions(containerClassname, searchId) {
if (!containerClassname || !this.impressionsDetectors[containerClassname]) {
console.error('Impossible to restart impression to unknown containerClassname')
throw new Error('unknown-container')
}
this.impressionsDetectors[containerClassname].restart({ search_id: searchId })
}
public whoami() {
return this.user_id
}
public generateSearchId(isNewSearch: boolean) {
if (isNewSearch) {
this.searchId = `${this.deviceId}${this.user_id}${Date.now()}`
}
return this.searchId
}
public setCurrentBlock(block: ContentBlock) {
// the reason of this delay is that the page event is triggered
// 10 miliseconds after it really happens to wait for the title
setTimeout(() => {
this.currentBlock = block
}, 15)
}
public setTitle(title: string) {
// do nothing yet
}
}