From 1796b08a8722cee64c3e48dc66c90ebd639861b3 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Thu, 11 Jan 2024 17:03:57 +0100 Subject: [PATCH] fix(tracker): expose canvas tracking restart method, remove context creation in assist --- tracker/tracker-assist/CHANGELOG.md | 4 ++++ tracker/tracker-assist/src/Canvas.ts | 1 - tracker/tracker/CHANGELOG.md | 9 +++++++++ tracker/tracker/src/main/app/canvas.ts | 18 +++++++++++++---- tracker/tracker/src/main/app/index.ts | 27 ++++++++++++++++++-------- tracker/tracker/src/main/index.ts | 7 +++++++ 6 files changed, 53 insertions(+), 13 deletions(-) diff --git a/tracker/tracker-assist/CHANGELOG.md b/tracker/tracker-assist/CHANGELOG.md index 4422b4446..464985ec8 100644 --- a/tracker/tracker-assist/CHANGELOG.md +++ b/tracker/tracker-assist/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.0.3 + +- small fix for canvas context tracking + ## 7.0.1 - mark live sessions with ux test active diff --git a/tracker/tracker-assist/src/Canvas.ts b/tracker/tracker-assist/src/Canvas.ts index 068ecaa26..7d6c13c54 100644 --- a/tracker/tracker-assist/src/Canvas.ts +++ b/tracker/tracker-assist/src/Canvas.ts @@ -9,7 +9,6 @@ export default class CanvasRecorder { private readonly onStream: (stream: MediaStream) => void, private readonly logError: (...args: any[]) => void, ) { - this.canvas.getContext('2d', { alpha: true, }) const stream = this.canvas.captureStream(this.fps) this.emitStream(stream) } diff --git a/tracker/tracker/CHANGELOG.md b/tracker/tracker/CHANGELOG.md index 28a3c3149..d56ae2ea3 100644 --- a/tracker/tracker/CHANGELOG.md +++ b/tracker/tracker/CHANGELOG.md @@ -4,6 +4,15 @@ - conditional recording with 30s buffer - websockets tracking hook +# 11.0.5 + +- add method to restart canvas tracking (in case of context recreation) +- scan dom tree for canvas els on tracker start + +# 11.0.4 + +- some additional security for canvas capture (check if canvas el itself is obscured/ignored) + # 11.0.3 - move all logs under internal debugger diff --git a/tracker/tracker/src/main/app/canvas.ts b/tracker/tracker/src/main/app/canvas.ts index 43c809155..fa54c6772 100644 --- a/tracker/tracker/src/main/app/canvas.ts +++ b/tracker/tracker/src/main/app/canvas.ts @@ -10,6 +10,7 @@ interface CanvasSnapshot { interface Options { fps: number quality: 'low' | 'medium' | 'high' + isDebug?: boolean } class CanvasRecorder { @@ -25,10 +26,17 @@ class CanvasRecorder { } startTracking() { + setTimeout(() => { + this.app.nodes.scanTree(this.handleCanvasEl) + this.app.nodes.attachNodeCallback((node: Node): void => { + this.handleCanvasEl(node) + }) + }, 500) + } + + restartTracking = () => { + this.clear() this.app.nodes.scanTree(this.handleCanvasEl) - this.app.nodes.attachNodeCallback((node: Node): void => { - this.handleCanvasEl(node) - }) } handleCanvasEl = (node: Node) => { @@ -74,7 +82,9 @@ class CanvasRecorder { images.forEach((snapshot) => { const blob = dataUrlToBlob(snapshot.data)[0] formData.append('snapshot', blob, `${createdAt}_${canvasId}_${snapshot.id}.jpeg`) - // saveImageData(snapshot.data, `${createdAt}_${canvasId}_${snapshot.id}.jpeg`) + if (this.options.isDebug) { + saveImageData(snapshot.data, `${createdAt}_${canvasId}_${snapshot.id}.jpeg`) + } }) fetch(this.app.options.ingestPoint + '/v1/web/images', { diff --git a/tracker/tracker/src/main/app/index.ts b/tracker/tracker/src/main/app/index.ts index fcf399837..869689959 100644 --- a/tracker/tracker/src/main/app/index.ts +++ b/tracker/tracker/src/main/app/index.ts @@ -115,6 +115,7 @@ type AppOptions = { __is_snippet: boolean __debug_report_edp: string | null __debug__?: ILogLevel + __save_canvas_locally?: boolean localStorage: Storage | null sessionStorage: Storage | null forceSingleTab?: boolean @@ -202,6 +203,7 @@ export default class App { __is_snippet: false, __debug_report_edp: null, __debug__: LogLevel.Silent, + __save_canvas_locally: false, localStorage: null, sessionStorage: null, disableStringDict: false, @@ -629,6 +631,7 @@ export default class App { return needNewSessionID || !sessionToken } + /** * start buffering messages without starting the actual session, which gives * user 30 seconds to "activate" and record session by calling `start()` on conditional trigger @@ -1050,6 +1053,17 @@ export default class App { void this.featureFlags.reloadFlags() this.activityState = ActivityState.Active + if (canvasEnabled) { + this.canvasRecorder = + this.canvasRecorder ?? + new CanvasRecorder(this, { + fps: canvasFPS, + quality: canvasQuality, + isDebug: this.options.__save_canvas_locally, + }) + this.canvasRecorder.startTracking() + } + /** --------------- COLD START BUFFER ------------------*/ if (isColdStart) { const biggestBuffer = @@ -1067,13 +1081,6 @@ export default class App { this.ticker.start() } - if (canvasEnabled) { - this.canvasRecorder = - this.canvasRecorder ?? - new CanvasRecorder(this, { fps: canvasFPS, quality: canvasQuality }) - this.canvasRecorder.startTracking() - } - // get rid of onStart ? if (typeof this.options.onStart === 'function') { this.options.onStart(onStartInfo) @@ -1126,6 +1133,10 @@ export default class App { }) } + restartCanvasTracking = () => { + this.canvasRecorder?.restartTracking() + } + flushBuffer = async (buffer: Message[]) => { return new Promise((res) => { let ended = false @@ -1196,7 +1207,7 @@ export default class App { /** * Creates a named hook that expects event name, data string and msg direction (up/down), * it will skip any message bigger than 5 mb or event name bigger than 255 symbols - * @returns {(msgType: string, data: string, dir: 'up' | 'down') => void} + * @returns {(msgType: string, data: string, dir: "up" | "down") => void} * */ trackWs(channelName: string): (msgType: string, data: string, dir: 'up' | 'down') => void { const channel = channelName diff --git a/tracker/tracker/src/main/index.ts b/tracker/tracker/src/main/index.ts index 4263525e3..6f76acbf6 100644 --- a/tracker/tracker/src/main/index.ts +++ b/tracker/tracker/src/main/index.ts @@ -254,6 +254,13 @@ export default class API { return this.app?.featureFlags.flags } + public restartCanvasTracking = () => { + if (this.app === null) { + return + } + this.app.restartCanvasTracking() + } + use(fn: (app: App | null, options?: Options) => T): T { return fn(this.app, this.options) }