UNPKG

@benshi.ai/js-sdk

Version:

Benshi SDK

170 lines (136 loc) 5.22 kB
import {NetworkProxy} from '../drivers/network/typings' import {debug, Debug} from '../logging' import {v4 as uuidv4} from 'uuid'; import {AppInfoObject, DeviceInfoObject, Event, EventMainObject, LogIngestorOptions, QueueItem} from "./typings" import {getAppDetails, getDeviceDetails, getNetworkInformation} from "../drivers/BsSystem"; import {version} from '../../package.json' export interface ISenderRepository { add(userId: string, deviceId: string, event: Event, forceSend: boolean): void flush() } export default class BsSender implements ISenderRepository { private flushing: boolean = false private flushIntervalId: number = 0 private bsNetwork private debug private options private endpointURL private userId: string = "" private deviceId: string = "" private queue: QueueItem[] public constructor( bsNetwork: NetworkProxy, options: LogIngestorOptions ) { this.queue = [] this.bsNetwork = bsNetwork this.options = options this.debug = debug(this.options.debug) // to avoid short timeout to save cpu usage if (this.options.flushInterval < 1000) { this.options.flushInterval = 1000 } if (this.options.cacheEventsInLocalstorage && typeof Storage !== 'undefined') { try { this.queue = JSON.parse(localStorage.getItem(this.options.cacheEventsKey) || '[]') as QueueItem[] } catch (e) { this.debug(Debug.Error, `Error getting queue items from cache ${e.message || ''}`) } } this.endpointURL = `${this.options.baseUrl}${this.options.ingestPath}` this.updateQueueCache() this.flushIntervalId = +setInterval(() => { this.flush() }, this.options.flushInterval) } public flush() { const flushItems = [...this.queue] if (flushItems.length === 0) { this.debug(Debug.Log, 'Skip sending empty list of logs ') return } const uuids: string[] = flushItems.map((item: QueueItem) => item.uuid) const data = flushItems.map((item: QueueItem) => item.event) this.flushing = true this.send(data, uuids) } public add(userId: string, deviceId: string, event: Event, forceSend: boolean = false) { const item: QueueItem = { uuid: uuidv4(), event, time: +new Date(), retries: 0 } this.userId = userId this.deviceId = deviceId this.queue.push(item) this.updateQueueCache() // send immediately. In case of error, it was already enqueued // so will be tried again in interval tick if (forceSend) { this.send([item.event], [item.uuid]) } } private removeQueueItemsExceedMaxRetries() { this.queue = this.queue.filter((item: QueueItem) => item.retries <= this.options.flushMaxRetries) } private removeFromQueue(uuids: string[]) { this.queue = this.queue.filter((item: QueueItem) => uuids.indexOf(item.uuid) === -1) this.updateQueueCache() } private updateQueueCache() { if (this.options.cacheEventsInLocalstorage && typeof Storage !== 'undefined') { localStorage.setItem(this.options.cacheEventsKey, JSON.stringify(this.queue)) } } private addRetries(uuids: string[]) { const time = +(new Date()) this.queue .filter((item: QueueItem) => uuids.indexOf(item.uuid) !== -1) .forEach((item: QueueItem) => { item.retries = (+item.retries) + 1 item.lastRetry = time }) this.updateQueueCache() } private send(dataList: Event[], uuids: string[]) { const {downlink, uplink} = getNetworkInformation() const deviceObject: DeviceInfoObject = { id: this.deviceId, ...getDeviceDetails() } const appObject: AppInfoObject = { id: document.location.host || "NO_URL_FOUND", min_sdk_version: 0, target_sdk_version: 0, ...getAppDetails() } const eventMainObject: EventMainObject = { s_id: this.generateSessionID(this.userId), u_id: this.userId, app_info: appObject, d_info: deviceObject, sdk: `jsBshXCF/${version}`, up: uplink, dn: downlink, data: dataList } return this.bsNetwork.send(this.endpointURL, eventMainObject) .then(() => { this.debug(Debug.Info, `Flushed ${dataList.length} events`) this.removeFromQueue(uuids) }) .catch((e) => { this.addRetries(uuids) this.debug(Debug.Error, e.message || '') }) .finally(() => { this.flushing = false this.removeQueueItemsExceedMaxRetries() }) } private generateSessionID(userId: string) { // return `${userId}_${startTimeInMillis}_${endTimeInMillis}`; return `${userId}_0_0`; } }