Skip to content

Commit

Permalink
Anthony/hig 190 move rrweb getactivityinterval logic (#28)
Browse files Browse the repository at this point in the history
* Added support for inactive threshold

* Updated version num

* Prettified

* Fixed names

* Fixed name

* Renamed

* Cleaned code and added handling for edge cases

* Updated package num

* More skip customize, changed cursor

* Update package version

* Changed to use webpack instead of rollup

Co-authored-by: Jay Khatri <j@jaykhatri.com>

* Fixed files

* Added missing styles from CDN

* Moved activity intervals calculation

* Updated version

* Only calculate intervals once

* Updated version

Co-authored-by: Jay Khatri <j@jaykhatri.com>
  • Loading branch information
eightants and jay-khatri authored Mar 4, 2021
1 parent acc2624 commit d6a0238
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 81 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@highlight-run/rrweb",
"version": "0.9.28",
"version": "0.9.29",
"description": "record and replay the web",
"scripts": {
"test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register test/**/*.test.ts",
Expand Down
163 changes: 83 additions & 80 deletions src/replay/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export class Replayer {

private emitter: Emitter = mitt();

private activityIntervals: Array<SessionInterval> = [];
private inactiveEndTimestamp: number | null;

// tslint:disable-next-line: variable-name
Expand Down Expand Up @@ -287,95 +288,97 @@ export class Replayer {
}

public getActivityIntervals(): Array<SessionInterval> {
// Preprocessing to get all active/inactive segments in a session
const allIntervals: Array<SessionInterval> = [];
const metadata = this.getMetaData();
const userInteractionEvents = [
{ timestamp: metadata.startTime },
...this.service.state.context.events.filter((ev) =>
this.isUserInteraction(ev),
),
{ timestamp: metadata.endTime },
];
for (let i = 1; i < userInteractionEvents.length; i++) {
const currentInterval = userInteractionEvents[i - 1];
const _event = userInteractionEvents[i];
if (
_event.timestamp! - currentInterval.timestamp! >
SKIP_TIME_THRESHOLD
) {
allIntervals.push({
startTime: currentInterval.timestamp!,
endTime: _event.timestamp!,
duration: _event.timestamp! - currentInterval.timestamp!,
active: false,
});
} else {
allIntervals.push({
startTime: currentInterval.timestamp!,
endTime: _event.timestamp!,
duration: _event.timestamp! - currentInterval.timestamp!,
active: true,
});
if (this.activityIntervals.length == 0) {
// Preprocessing to get all active/inactive segments in a session
const allIntervals: Array<SessionInterval> = [];
const metadata = this.getMetaData();
const userInteractionEvents = [
{ timestamp: metadata.startTime },
...this.service.state.context.events.filter((ev) =>
this.isUserInteraction(ev),
),
{ timestamp: metadata.endTime },
];
for (let i = 1; i < userInteractionEvents.length; i++) {
const currentInterval = userInteractionEvents[i - 1];
const _event = userInteractionEvents[i];
if (
_event.timestamp! - currentInterval.timestamp! >
SKIP_TIME_THRESHOLD
) {
allIntervals.push({
startTime: currentInterval.timestamp!,
endTime: _event.timestamp!,
duration: _event.timestamp! - currentInterval.timestamp!,
active: false,
});
} else {
allIntervals.push({
startTime: currentInterval.timestamp!,
endTime: _event.timestamp!,
duration: _event.timestamp! - currentInterval.timestamp!,
active: true,
});
}
}
}
// Merges continuous active/inactive ranges
const mergedIntervals: Array<SessionInterval> = [];
let currentInterval = allIntervals[0];
for (let i = 1; i < allIntervals.length; i++) {
if (allIntervals[i].active != allIntervals[i - 1].active) {
// Merges continuous active/inactive ranges
const mergedIntervals: Array<SessionInterval> = [];
let currentInterval = allIntervals[0];
for (let i = 1; i < allIntervals.length; i++) {
if (allIntervals[i].active != allIntervals[i - 1].active) {
mergedIntervals.push({
startTime: currentInterval.startTime,
endTime: allIntervals[i - 1].endTime,
duration: allIntervals[i - 1].endTime - currentInterval.startTime,
active: allIntervals[i - 1].active,
});
currentInterval = allIntervals[i];
}
}
if (currentInterval && allIntervals.length > 0) {
mergedIntervals.push({
startTime: currentInterval.startTime,
endTime: allIntervals[i - 1].endTime,
duration: allIntervals[i - 1].endTime - currentInterval.startTime,
active: allIntervals[i - 1].active,
endTime: allIntervals[allIntervals.length - 1].endTime,
duration:
allIntervals[allIntervals.length - 1].endTime -
currentInterval.startTime,
active: allIntervals[allIntervals.length - 1].active,
});
currentInterval = allIntervals[i];
}
}
if (currentInterval && allIntervals.length > 0) {
mergedIntervals.push({
startTime: currentInterval.startTime,
endTime: allIntervals[allIntervals.length - 1].endTime,
duration:
allIntervals[allIntervals.length - 1].endTime -
currentInterval.startTime,
active: allIntervals[allIntervals.length - 1].active,
});
}
// Merges inactive segments that are less than a threshold into surrounding active sessions
// TODO: Change this from a 3n pass to n
const activityIntervals: Array<SessionInterval> = [];
currentInterval = mergedIntervals[0];
for (let i = 1; i < mergedIntervals.length; i++) {
if (
(!mergedIntervals[i].active &&
mergedIntervals[i].duration >
this.config.inactiveThreshold * metadata.totalTime) ||
(!mergedIntervals[i - 1].active &&
mergedIntervals[i - 1].duration >
this.config.inactiveThreshold * metadata.totalTime)
) {
activityIntervals.push({
// Merges inactive segments that are less than a threshold into surrounding active sessions
// TODO: Change this from a 3n pass to n
currentInterval = mergedIntervals[0];
for (let i = 1; i < mergedIntervals.length; i++) {
if (
(!mergedIntervals[i].active &&
mergedIntervals[i].duration >
this.config.inactiveThreshold * metadata.totalTime) ||
(!mergedIntervals[i - 1].active &&
mergedIntervals[i - 1].duration >
this.config.inactiveThreshold * metadata.totalTime)
) {
this.activityIntervals.push({
startTime: currentInterval.startTime,
endTime: mergedIntervals[i - 1].endTime,
duration:
mergedIntervals[i - 1].endTime - currentInterval.startTime,
active: mergedIntervals[i - 1].active,
});
currentInterval = mergedIntervals[i];
}
}
if (currentInterval && mergedIntervals.length > 0) {
this.activityIntervals.push({
startTime: currentInterval.startTime,
endTime: mergedIntervals[i - 1].endTime,
duration: mergedIntervals[i - 1].endTime - currentInterval.startTime,
active: mergedIntervals[i - 1].active,
endTime: mergedIntervals[mergedIntervals.length - 1].endTime,
duration:
mergedIntervals[mergedIntervals.length - 1].endTime -
currentInterval.startTime,
active: mergedIntervals[mergedIntervals.length - 1].active,
});
currentInterval = mergedIntervals[i];
}
}
if (currentInterval && mergedIntervals.length > 0) {
activityIntervals.push({
startTime: currentInterval.startTime,
endTime: mergedIntervals[mergedIntervals.length - 1].endTime,
duration:
mergedIntervals[mergedIntervals.length - 1].endTime -
currentInterval.startTime,
active: mergedIntervals[mergedIntervals.length - 1].active,
});
}
return activityIntervals;
return this.activityIntervals;
}

public getMetaData(): playerMetaData {
Expand Down

0 comments on commit d6a0238

Please sign in to comment.