generated from ipfs/ipfs-repository-template
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #65 from ipfs-shipyard/feat/accumulate-events
feat: Accumulate Events
- Loading branch information
Showing
22 changed files
with
3,857 additions
and
2,266 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
root=true | ||
|
||
[*] | ||
end_of_line = lf | ||
insert_final_newline = true | ||
charset = utf-8 | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"extensions": ["ts"], | ||
"spec": ["test/**/*.spec.*"], | ||
"require": ["ts-node/register"], | ||
"node-option": [ | ||
"experimental-specifier-resolution=node", | ||
"loader=ts-node/esm" | ||
] | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
import type { CountlyEvent, CountlyEventData, CountlyWebSdk, IEventAccumulator } from 'countly-sdk-web' | ||
import type { CountlyNodeSdk } from 'countly-sdk-nodejs' | ||
|
||
const eventDefaults: CountlyEventData = { | ||
key: '', | ||
count: 1, | ||
sum: 1, | ||
dur: 0, | ||
segmentation: {} | ||
} | ||
|
||
interface eventStore { | ||
eventData: CountlyEventData | ||
startTime: number | ||
timeout: NodeJS.Timeout | ||
} | ||
|
||
/** | ||
* EventAccumulator is a class that accumulates events and flushes them to the Countly server. | ||
*/ | ||
export class EventAccumulator<T extends CountlyWebSdk | CountlyNodeSdk> implements IEventAccumulator { | ||
private readonly metricsService: T | ||
private readonly events: Map<string, eventStore> = new Map() | ||
private readonly flushInterval: number | ||
|
||
/** | ||
* Create a new EventAccumulator | ||
* | ||
* @param {CountlyWebSdk} metricsService - instance | ||
* @param {number} flushInterval - in milliseconds | ||
*/ | ||
constructor (metricsService: T, flushInterval: number = 5 * 60 * 1000) { | ||
this.metricsService = metricsService | ||
this.flushInterval = flushInterval | ||
this.setupUnloadEvent() | ||
} | ||
|
||
/** | ||
* Setup the beforeunload event to flush all events. | ||
*/ | ||
private setupUnloadEvent (): void { | ||
const flushAllHandler = (): void => { | ||
this.flushAll() | ||
} | ||
|
||
if (typeof globalThis.addEventListener === 'function') { | ||
globalThis.addEventListener('beforeunload', flushAllHandler) | ||
} else if (typeof globalThis.process?.on === 'function') { | ||
globalThis.process.on('beforeExit', flushAllHandler) | ||
} | ||
} | ||
|
||
/** | ||
* Pad events with default values | ||
* | ||
* @param {CountlyEvent} event - event to add defaults to | ||
* @returns {CountlyEventData} - event with defaults added | ||
*/ | ||
private addEventDefaults (event: CountlyEvent): CountlyEventData { | ||
return { ...eventDefaults, ...event } | ||
} | ||
|
||
/** | ||
* Setup the event accumulator for a key type for the first time. | ||
* | ||
* @param {CountlyEventData} eventData - event data | ||
*/ | ||
private setupEventAccumulator (eventData: CountlyEventData): void { | ||
const { key } = eventData | ||
this.events.set(key, { | ||
eventData, | ||
// set start time to now. This will be updated when the event is flushed. | ||
startTime: Date.now(), | ||
// set a timeout to flush the event after the flush interval. | ||
timeout: setTimeout(() => { | ||
this.flush(key) | ||
}, this.flushInterval) | ||
}) | ||
} | ||
|
||
/** | ||
* Digest only the event data from an event. | ||
* | ||
* @param {CountlyEventData} newEventData - event data | ||
*/ | ||
private accumulateEventData (newEventData: CountlyEventData): void { | ||
const { key, count, segmentation } = newEventData | ||
// if event is in the store, update the event data. | ||
const eventStore = this.events.get(key) | ||
if (eventStore == null) { | ||
this.setupEventAccumulator(newEventData) | ||
return | ||
} | ||
const { eventData } = eventStore | ||
eventData.count += count | ||
eventData.sum += 1 | ||
eventData.segmentation = { ...eventData.segmentation, ...segmentation } | ||
} | ||
|
||
/** | ||
* Add an event to the accumulator | ||
* | ||
* @param {CountlyEvent} event - event to add | ||
* @param {boolean} flush - optionally whether to flush the event immediately | ||
*/ | ||
addEvent (event: CountlyEvent, flush: boolean = false): void { | ||
const eventData = this.addEventDefaults(event) | ||
const { key } = eventData | ||
|
||
// validate event | ||
if (key === '') { | ||
throw new Error('Event key is required.') | ||
} | ||
|
||
this.accumulateEventData(eventData) | ||
|
||
// flush the event if flush is true. | ||
if (flush) { | ||
this.flush(key) | ||
} | ||
} | ||
|
||
/** | ||
* Flush an event from the accumulator | ||
* | ||
* @param {string} key - event key | ||
*/ | ||
flush (key: string): void { | ||
const eventStore = this.events.get(key) | ||
if (eventStore == null) { | ||
return | ||
} | ||
|
||
const { eventData, startTime, timeout } = eventStore | ||
|
||
// update duration to ms from start. | ||
eventData.dur = Date.now() - startTime | ||
// add event to the async queue. | ||
this.metricsService.add_event(eventData) | ||
clearTimeout(timeout) | ||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete | ||
this.events.delete(key) | ||
} | ||
|
||
/** | ||
* Flush all events from the accumulator | ||
*/ | ||
flushAll (): void { | ||
this.events.forEach((_, key) => { | ||
this.flush(key) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.