From 8251aecede83d97a389a35672654610f52ec90d0 Mon Sep 17 00:00:00 2001 From: Delirium Date: Thu, 25 Apr 2024 10:09:30 +0200 Subject: [PATCH] fix tracler: improved logs for node binding errors, full nodelist clear before start, state check, getSessionInfo method * fix tracker: some extra debug logs and safety around node mapping * fix tracker: some extra debug logs and safety around node mapping * white spaces * cleanup * new fifo scheduler * node clearing and start check * new sess info method, better session start logging * snippet beta --- frontend/app/player/web/MessageLoader.ts | 4 +- tracker/tracker-assist/bun.lockb | Bin 248080 -> 250563 bytes tracker/tracker/CHANGELOG.md | 4 + tracker/tracker/package.json | 2 +- tracker/tracker/src/main/app/index.ts | 33 +++++-- tracker/tracker/src/main/app/nodes.ts | 1 + .../tracker/src/main/app/observer/observer.ts | 10 ++- .../src/main/app/observer/top_observer.ts | 1 + tracker/tracker/src/main/app/session.ts | 2 +- tracker/tracker/src/main/index.ts | 8 ++ tracker/tracker/src/main/utils.ts | 83 +++++++++++++----- tracker/tracker/src/tests/utils.unit.test.ts | 43 +++------ 12 files changed, 125 insertions(+), 66 deletions(-) diff --git a/frontend/app/player/web/MessageLoader.ts b/frontend/app/player/web/MessageLoader.ts index 35dbcfe4d..3131029d8 100644 --- a/frontend/app/player/web/MessageLoader.ts +++ b/frontend/app/player/web/MessageLoader.ts @@ -84,7 +84,9 @@ export default class MessageLoader { msg.time = msg.actionTime - this.session.startedAt; } else { // @ts-ignore - Object.assign(msg, { actionTime: msg.time + this.session.startedAt }); + Object.assign(msg, { + actionTime: msg.time + this.session.startedAt, + }); } } if ( diff --git a/tracker/tracker-assist/bun.lockb b/tracker/tracker-assist/bun.lockb index 378da5fb7ab0bf091d41db04efed6635082eb7d6..6dea11a765d7559ba081b8c9ed8b3048bf343076 100755 GIT binary patch delta 10205 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

gQZc&Hr%r zQ#k+?fo(>d0^NXp6S@WQk2>?AMG*gxG#i=&je&++;Hf+cMp>Q6icvc{abGqE;uecr zs`*fY_+)}wT?9^0U0trAgSVi|sQ4PhHNpAL6bbbCZi1R4k|(NFI`%+jI1~nrf+CvA^vG=EEECtN5y%X_<5pQUzDDt)>5ri(Pol5!*UE9Z;PKM zsdbl5R-N1MDR>UZ4rS~iM~L49o?*ewhL%82;p2t+cyj(4;-R$`^cHzHHQ_#4t>az= z`CR-#;5<+8TyPLN4h=^As}M7P1mckvqW@&ILNjg?xjSD5ok3m%(tHbJH*MNH?}ohx zdJVmS-b3~}F=MjYtv+v{l85C;_z!~GLu`ZMHn9`bK_^zls+C;0qgxN9K!=der?xxP zNKB7WD~dN53;l=8g-P~J#Iji2Hhc;NLnRNMlKAf`k>>$< zLVOQ2h5R6HI$1xTc0tfl=s3i8e*rY{ANfs?_LR(Q2r7I~i52FBugx{$My%>+VEt>P z%-b?6uW$(er@sEv*B5>8hI}9oi0>zN$lOnkLA4Jc8#*g5%+x8dGFGkZL0mFs=6x(- z{~X`qOA`-c)zVJpZL%I#yId6E(%nmno4YW(gwx(EAEi&{idEy(Iu`thm+du0Enn8R zAFk**T>2vBS=JhQj}|yfp|C@sL$JB{7a`^i+662id-_~;s?Mqn?0iMo&sY8MUum!? zp|(&U)By^D+ClB18K|R^7(HLDZr~aIGbG=jx^A%9BR0ooyUMsb;xMQ;)C;miUQfi~ z&^?r`hM31{cA*axAQ?x3WmqSDrX$VQG7qPfkglRC6-@8l!AJ~*_?ebx?EXSGPi@|W zs6T||W!h)3TnYQz75T1w0wToNh^q-|oot&0>XQhaNA{n8s(Wp8^F_8!3-b1LZw41z zyhSmB@tN-*KC`X#Lv0J4mwRze9pqF;PU!N-kNwvazLPnk-+Q&91zki}RjZ)E5{W>v zzO^V-1EuCIe4CtI)8YPq>nlJ`HRRlBUEAi5fWSi~^Tl2&+rgQSd2`i+(&l7j7w7{BY z^Gsi9{{9b61(!lR9PFb`tGfQ4?w;U3Ez4~j z!sKJw^~-4eH;O+Tv>Mr4Gqg`jIbvSiV@6EzkBJ>OEV|LK=$NQsVtTk%MRYCDoW#={ zttNW*G*hb~&g5(MOLH_ULJQF)SF38CBjWRsWysNNMDqh$<&vzYhf&MI16rjLz*>ZV zj^-eG { - this.messages.unshift(TabData(this.session.getTabId())) - this.messages.unshift(Timestamp(this.timestamp())) - // why I need to add opt chaining? - this.worker?.postMessage(this.messages) - this.commitCallbacks.forEach((cb) => cb(this.messages)) - this.messages.length = 0 - }) + try { + requestIdleCb(() => { + this.messages.unshift(TabData(this.session.getTabId())) + this.messages.unshift(Timestamp(this.timestamp())) + // why I need to add opt chaining? + this.worker?.postMessage(this.messages) + this.commitCallbacks.forEach((cb) => cb(this.messages)) + this.messages.length = 0 + }) + } catch (e) { + this._debug('worker_commit', e) + this.stop(true) + setTimeout(() => { + void this.start() + }, 500) + } } } @@ -1177,6 +1185,15 @@ export default class App { * and here we just apply 10ms delay just in case * */ start(...args: Parameters): Promise { + if ( + this.activityState === ActivityState.Active || + this.activityState === ActivityState.Starting + ) { + const reason = + 'OpenReplay: trying to call `start()` on the instance that has been started already.' + return Promise.resolve(UnsuccessfulStart(reason)) + } + if (!document.hidden) { return new Promise((resolve) => { setTimeout(() => { diff --git a/tracker/tracker/src/main/app/nodes.ts b/tracker/tracker/src/main/app/nodes.ts index 92612d2e5..b2b9cc136 100644 --- a/tracker/tracker/src/main/app/nodes.ts +++ b/tracker/tracker/src/main/app/nodes.ts @@ -49,6 +49,7 @@ export default class Nodes { unregisterNode(node: Node): number | undefined { const id = (node as any)[this.node_id] if (id !== undefined) { + ;(node as any)[this.node_id] = undefined delete (node as any)[this.node_id] delete this.nodes[id] const listeners = this.elementListeners.get(id) diff --git a/tracker/tracker/src/main/app/observer/observer.ts b/tracker/tracker/src/main/app/observer/observer.ts index da02138ab..adbada4e9 100644 --- a/tracker/tracker/src/main/app/observer/observer.ts +++ b/tracker/tracker/src/main/app/observer/observer.ts @@ -206,10 +206,14 @@ export default abstract class Observer { node, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, { - acceptNode: (node) => - isIgnored(node) || this.app.nodes.getID(node) !== undefined + acceptNode: (node) => { + if (this.app.nodes.getID(node) !== undefined) { + this.app.debug.error('! Node is already bound', node) + } + return isIgnored(node) || this.app.nodes.getID(node) !== undefined ? NodeFilter.FILTER_REJECT - : NodeFilter.FILTER_ACCEPT, + : NodeFilter.FILTER_ACCEPT + }, }, // @ts-ignore false, diff --git a/tracker/tracker/src/main/app/observer/top_observer.ts b/tracker/tracker/src/main/app/observer/top_observer.ts index f5db56549..24cb3e270 100644 --- a/tracker/tracker/src/main/app/observer/top_observer.ts +++ b/tracker/tracker/src/main/app/observer/top_observer.ts @@ -122,6 +122,7 @@ export default class TopObserver extends Observer { return shadow } + this.app.nodes.clear() // Can observe documentElement () here, because it is not supposed to be changing. // However, it is possible in some exotic cases and may cause an ignorance of the newly created // In this case context.document have to be observed, but this will cause diff --git a/tracker/tracker/src/main/app/session.ts b/tracker/tracker/src/main/app/session.ts index 2580843b9..7a5ca81c1 100644 --- a/tracker/tracker/src/main/app/session.ts +++ b/tracker/tracker/src/main/app/session.ts @@ -10,7 +10,7 @@ interface UserInfo { userState: string } -interface SessionInfo { +export interface SessionInfo { sessionID: string | undefined metadata: Record userID: string | null diff --git a/tracker/tracker/src/main/index.ts b/tracker/tracker/src/main/index.ts index daae49b32..933ec08e0 100644 --- a/tracker/tracker/src/main/index.ts +++ b/tracker/tracker/src/main/index.ts @@ -39,6 +39,7 @@ import type { Options as PerformanceOptions } from './modules/performance.js' import type { Options as TimingOptions } from './modules/timing.js' import type { Options as NetworkOptions } from './modules/network.js' import type { MouseHandlerOptions } from './modules/mouse.js' +import type { SessionInfo } from './app/session.js' import type { StartOptions } from './app/index.js' //TODO: unique options init @@ -381,6 +382,13 @@ export default class API { return this.app.getSessionToken() } + getSessionInfo(): SessionInfo | null { + if (this.app === null) { + return null + } + return this.app.session.getInfo() + } + getSessionID(): string | null | undefined { if (this.app === null) { return null diff --git a/tracker/tracker/src/main/utils.ts b/tracker/tracker/src/main/utils.ts index 9dd27a21c..15946b4a6 100644 --- a/tracker/tracker/src/main/utils.ts +++ b/tracker/tracker/src/main/utils.ts @@ -167,27 +167,70 @@ export function deleteEventListener( } } -/** - * This is a brief polyfill that suits our needs - * I took inspiration from Microsoft Clarity polyfill on this one - * then adapted it a little bit - * - * I'm very grateful for their bright idea - * */ -export function requestIdleCb(callback: () => void) { - const taskTimeout = 3000 - if (window.requestIdleCallback) { - return window.requestIdleCallback(callback, { timeout: taskTimeout }) - } else { - const channel = new MessageChannel() - const incoming = channel.port1 - const outgoing = channel.port2 - incoming.onmessage = (): void => { - callback() +class FIFOTaskScheduler { + taskQueue: any[] + isRunning: boolean + constructor() { + this.taskQueue = [] + this.isRunning = false + } + + // Adds a task to the queue + addTask(task: () => any) { + this.taskQueue.push(task) + this.runTasks() + } + + // Runs tasks from the queue + runTasks() { + if (this.isRunning || this.taskQueue.length === 0) { + return } - requestAnimationFrame((): void => { - outgoing.postMessage(1) - }) + + this.isRunning = true + + const executeNextTask = () => { + if (this.taskQueue.length === 0) { + this.isRunning = false + return + } + + // Get the next task and execute it + const nextTask = this.taskQueue.shift() + Promise.resolve(nextTask()).then(() => { + requestAnimationFrame(() => executeNextTask()) + }) + } + + executeNextTask() } } + +const scheduler = new FIFOTaskScheduler() +export function requestIdleCb(callback: () => void) { + // performance improvement experiment; + scheduler.addTask(callback) + /** + * This is a brief polyfill that suits our needs + * I took inspiration from Microsoft Clarity polyfill on this one + * then adapted it a little bit + * + * I'm very grateful for their bright idea + * */ + // const taskTimeout = 3000 + // if (window.requestIdleCallback) { + // return window.requestIdleCallback(callback, { timeout: taskTimeout }) + // } else { + // const channel = new MessageChannel() + // const incoming = channel.port1 + // const outgoing = channel.port2 + // + // incoming.onmessage = (): void => { + // callback() + // } + // requestAnimationFrame((): void => { + // outgoing.postMessage(1) + // }) + // } +} diff --git a/tracker/tracker/src/tests/utils.unit.test.ts b/tracker/tracker/src/tests/utils.unit.test.ts index 8aef77110..19d83418b 100644 --- a/tracker/tracker/src/tests/utils.unit.test.ts +++ b/tracker/tracker/src/tests/utils.unit.test.ts @@ -204,41 +204,20 @@ describe('ngSafeBrowserMethod', () => { }) describe('requestIdleCb', () => { - test('uses window.requestIdleCallback when available', () => { - const callback = jest.fn() + test('testing FIFO scheduler', async () => { + jest.useFakeTimers() // @ts-ignore - window.requestIdleCallback = callback + jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => cb()); + const cb1 = jest.fn() + const cb2 = jest.fn() - requestIdleCb(callback) + requestIdleCb(cb1) + requestIdleCb(cb2) - expect(callback).toBeCalled() - }) + expect(cb1).toBeCalled() + expect(cb2).toBeCalledTimes(0) + await jest.advanceTimersToNextTimerAsync(1) - test('falls back to using a MessageChannel if requestIdleCallback is not available', () => { - const callback = jest.fn() - class MessageChannelMock { - port1 = { - // @ts-ignore - postMessage: (v: any) => this.port2.onmessage(v), - onmessage: null, - } - port2 = { - onmessage: null, - // @ts-ignore - postMessage: (v: any) => this.port1.onmessage(v), - } - } - // @ts-ignore - globalThis.MessageChannel = MessageChannelMock - // @ts-ignore - globalThis.requestAnimationFrame = (cb: () => void) => cb() - // @ts-ignore - window.requestIdleCallback = undefined - - requestIdleCb(callback) - - // You can assert that the callback was called using the MessageChannel approach. - // This is more challenging to test, so it's recommended to mock MessageChannel. - expect(callback).toBeCalled() + expect(cb2).toBeCalledTimes(1) }) })