From d79a14f6d043002cb46d0f8e33c10585e5283b5e Mon Sep 17 00:00:00 2001 From: ShiKhu Date: Mon, 25 Apr 2022 19:06:09 +0200 Subject: [PATCH] fix(tracker):3.5.10:fix pre-start & resources duplication --- tracker/tracker/package.json | 2 +- tracker/tracker/src/main/app/index.ts | 65 ++++++++++------------ tracker/tracker/src/main/modules/timing.ts | 29 +++++----- 3 files changed, 44 insertions(+), 52 deletions(-) diff --git a/tracker/tracker/package.json b/tracker/tracker/package.json index 0c5b06634..555efe07d 100644 --- a/tracker/tracker/package.json +++ b/tracker/tracker/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker", "description": "The OpenReplay tracker main package", - "version": "3.5.9", + "version": "3.5.10", "keywords": [ "logging", "replay" diff --git a/tracker/tracker/src/main/app/index.ts b/tracker/tracker/src/main/app/index.ts index 8fd2cb4ac..ace8ecf6e 100644 --- a/tracker/tracker/src/main/app/index.ts +++ b/tracker/tracker/src/main/app/index.ts @@ -13,16 +13,8 @@ import { deviceMemory, jsHeapSizeLimit } from "../modules/performance.js"; import type { Options as ObserverOptions } from "./observer/top_observer.js"; import type { Options as SanitizerOptions } from "./sanitizer.js"; import type { Options as LoggerOptions } from "./logger.js" - - import type { Options as WebworkerOptions, WorkerMessageData } from "../../webworker/types.js"; -export interface OnStartInfo { - sessionID: string, - sessionToken: string, - userUUID: string, -} - // TODO: Unify and clearly describe options logic export interface StartOptions { @@ -31,6 +23,20 @@ export interface StartOptions { forceNew?: boolean, } +export interface OnStartInfo { + sessionID: string, + sessionToken: string, + userUUID: string, +} + +type StartCallback = (i: OnStartInfo) => void +type CommitCallback = (messages: Array) => void +enum ActivityState { + NotActive, + Starting, + Active, +} + type AppOptions = { revID: string; node_id: string; @@ -47,19 +53,11 @@ type AppOptions = { __debug__?: LoggerOptions; // @deprecated - onStart?: (info: OnStartInfo) => void; + onStart?: StartCallback; } & WebworkerOptions; export type Options = AppOptions & ObserverOptions & SanitizerOptions -type Callback = () => void -type CommitCallback = (messages: Array) => void -enum ActivityState { - NotActive, - Starting, - Active, -} - export const CANCELED = "canceled" // TODO: use backendHost only @@ -75,8 +73,8 @@ export default class App { readonly session: Session; private readonly messages: Array = []; private readonly observer: Observer; - private readonly startCallbacks: Array = []; - private readonly stopCallbacks: Array = []; + private readonly startCallbacks: Array = []; + private readonly stopCallbacks: Array = []; private readonly commitCallbacks: Array = []; private readonly options: AppOptions; private readonly revID: string; @@ -167,20 +165,14 @@ export default class App { this.debug.error("OpenReplay error: ", context, e) } - private readonly preStartMessages: Message[] = [] send(message: Message, urgent = false): void { - if (this.activityState === ActivityState.NotActive) { - return; - } - if (this.activityState === ActivityState.Starting) { - this.preStartMessages.push(message); - } - if (this.preStartMessages.length) { - this.messages.push(...this.preStartMessages); - this.preStartMessages.length = 0 - } + if (this.activityState === ActivityState.NotActive) { return } this.messages.push(message); - if (urgent) { + // TODO: commit on start if there were `urgent` sends; + // Clearify where urgent can be used for; + // Clearify workflow for each type of message in case it was sent before start + // (like Fetch before start; maybe add an option "preCapture: boolean" or sth alike) + if (this.activityState === ActivityState.Active && urgent) { this.commit(); } } @@ -211,11 +203,10 @@ export default class App { attachCommitCallback(cb: CommitCallback): void { this.commitCallbacks.push(cb) } - - attachStartCallback(cb: Callback): void { + attachStartCallback(cb: StartCallback): void { this.startCallbacks.push(cb); } - attachStopCallback(cb: Callback): void { + attachStopCallback(cb: Function): void { this.stopCallbacks.push(cb); } attachEventListener( @@ -394,13 +385,15 @@ export default class App { beaconSizeLimit } this.worker.postMessage(startWorkerMsg) - this.startCallbacks.forEach((cb) => cb()); + + const onStartInfo = { sessionToken: token, userUUID, sessionID }; + + this.startCallbacks.forEach((cb) => cb(onStartInfo)); this.observer.observe(); this.ticker.start(); this.notify.log("OpenReplay tracking started."); // TODO: get rid of onStart - const onStartInfo = { sessionToken: token, userUUID, sessionID }; if (typeof this.options.onStart === 'function') { this.options.onStart(onStartInfo); } diff --git a/tracker/tracker/src/main/modules/timing.ts b/tracker/tracker/src/main/modules/timing.ts index 60e30019f..033741838 100644 --- a/tracker/tracker/src/main/modules/timing.ts +++ b/tracker/tracker/src/main/modules/timing.ts @@ -107,18 +107,6 @@ export default function (app: App, opts: Partial): void { } if (!options.captureResourceTimings) { return } // Resources are necessary for all timings - const mQueue: Message[] = [] - function sendOnStart(m: Message) { - if (app.active()) { - app.send(m) - } else { - mQueue.push(m) - } - } - app.attachStartCallback(function() { - mQueue.forEach(m => app.send(m)) - }) - let resources: ResourcesTimeMap | null = {} function resourceTiming(entry: PerformanceResourceTiming): void { @@ -126,7 +114,7 @@ export default function (app: App, opts: Partial): void { if (resources !== null) { resources[entry.name] = entry.startTime + entry.duration; } - sendOnStart(new + app.send(new ResourceTiming( entry.startTime + performance.timing.navigationStart, entry.duration, @@ -147,8 +135,19 @@ export default function (app: App, opts: Partial): void { const observer: PerformanceObserver = new PerformanceObserver( (list) => list.getEntries().forEach(resourceTiming), ) - performance.getEntriesByType('resource').forEach(resourceTiming) - observer.observe({ entryTypes: ['resource'] }) + + let prevSessionID: string | undefined + app.attachStartCallback(function({ sessionID }) { + if (sessionID !== prevSessionID) { // Send past page resources on a newly started session + performance.getEntriesByType('resource').forEach(resourceTiming) + prevSessionID = sessionID + } + observer.observe({ entryTypes: ['resource'] }) + }) + + app.attachStopCallback(function() { + observer.disconnect() + }) let firstPaint = 0,