diff --git a/tracker/tracker/package-lock.json b/tracker/tracker/package-lock.json index e08453206..e478e35c6 100644 --- a/tracker/tracker/package-lock.json +++ b/tracker/tracker/package-lock.json @@ -1,6 +1,6 @@ { - "name": "@asayerio/tracker", - "version": "5.6.5", + "name": "@openreplay/tracker", + "version": "3.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4513,9 +4513,9 @@ "dev": true }, "typescript": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", - "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", + "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==", "dev": true }, "unc-path-regex": { diff --git a/tracker/tracker/package.json b/tracker/tracker/package.json index 001789f90..4765ac2c5 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.0.4", + "version": "3.0.5", "keywords": [ "logging", "replay" @@ -18,9 +18,9 @@ "clean": "rm -Rf build && rm -Rf lib && rm -Rf cjs", "tsc": "tsc -b src/main && tsc -b src/webworker && tsc --project src/main/tsconfig-cjs.json", "rollup": "rollup --config rollup.config.js", - "compile": "node --experimental-modules --experimental-json-modules compile.js", + "compile": "node --experimental-modules --experimental-json-modules scripts/compile.js", "build": "npm run clean && npm run tsc && npm run rollup && npm run compile", - "prepare": "node checkver.cjs && npm run build" + "prepare": "node scripts/checkver.cjs && npm run build" }, "devDependencies": { "@babel/core": "^7.10.2", @@ -38,7 +38,7 @@ "rollup": "^2.17.0", "rollup-plugin-terser": "^6.1.0", "semver": "^6.3.0", - "typescript": "^3.9.5" + "typescript": "^4.3.4" }, "dependencies": { "error-stack-parser": "^2.0.6" diff --git a/tracker/tracker/src/main/modules/performance.ts b/tracker/tracker/src/main/modules/performance.ts index cefa6044b..2a4edd149 100644 --- a/tracker/tracker/src/main/modules/performance.ts +++ b/tracker/tracker/src/main/modules/performance.ts @@ -2,13 +2,19 @@ import App from '../app'; import { IN_BROWSER } from '../utils'; import { PerformanceTrack } from '../../messages'; -const perf: { - memory: { - jsHeapSizeLimit?: number; - totalJSHeapSize?: number; - usedJSHeapSize?: number; - }; -} = IN_BROWSER && 'memory' in performance ? performance : { memory: {} }; + +type Perf = { + memory: { + totalJSHeapSize?: number, + usedJSHeapSize?: number, + jsHeapSizeLimit?: number, + } +} + +const perf: Perf = IN_BROWSER && 'memory' in performance // works in Chrome only + ? performance as any + : { memory: {} } + export const deviceMemory = IN_BROWSER ? ((navigator as any).deviceMemory || 0) * 1024 : 0; export const jsHeapSizeLimit = perf.memory.jsHeapSizeLimit || 0; diff --git a/tracker/tracker/src/webworker/types.ts b/tracker/tracker/src/messages/webworker.ts similarity index 57% rename from tracker/tracker/src/webworker/types.ts rename to tracker/tracker/src/messages/webworker.ts index 22f55fad1..e5eb8eef7 100644 --- a/tracker/tracker/src/webworker/types.ts +++ b/tracker/tracker/src/messages/webworker.ts @@ -1,6 +1,8 @@ +// TODO: "common" folder instead of "messages". (better file structure) export interface Options { connAttemptCount?: number; connAttemptGap?: number; + beaconSize?: number; } type Settings = { @@ -11,4 +13,4 @@ type Settings = { timeAdjustment?: number; } & Partial; -export type MessageData = null | "stop" | Settings | Array<{ _id: number }>; \ No newline at end of file +export type WorkerMessageData = null | "stop" | Settings | Array<{ _id: number }>; \ No newline at end of file diff --git a/tracker/tracker/src/webworker/index.ts b/tracker/tracker/src/webworker/index.ts index 409a44b4e..271c13f2b 100644 --- a/tracker/tracker/src/webworker/index.ts +++ b/tracker/tracker/src/webworker/index.ts @@ -2,13 +2,15 @@ import { classes, BatchMeta, Timestamp, SetPageVisibility, CreateDocument } from import Message from '../messages/message'; import Writer from '../messages/writer'; -import type { MessageData } from './types'; +import type { WorkerMessageData } from '../messages/webworker'; + -// TODO: what if on message overflows? (maybe one option) -const MAX_BATCH_SIZE = 4 * 1e5; // Max 400kB const SEND_INTERVAL = 20 * 1000; +const BEACON_SIZE_LIMIT = 1e6 // Limit is set in the backend/services/http +let beaconSize = 4 * 1e5; // Default 400kB -const writer: Writer = new Writer(MAX_BATCH_SIZE); + +let writer: Writer = new Writer(beaconSize); let ingestPoint: string = ""; let token: string = ""; @@ -31,9 +33,12 @@ let busy = false; let attemptsCount = 0; let ATTEMPT_TIMEOUT = 8000; let MAX_ATTEMPTS_COUNT = 10; + +// TODO?: exploit https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon function sendBatch(batch: Uint8Array):void { const req = new XMLHttpRequest(); - req.open("POST", ingestPoint + "/v1/web/i"); // TODO opaque request? + // TODO: async=false (3d param) instead of sendQueue array ? + req.open("POST", ingestPoint + "/v1/web/i", false); // TODO opaque request? req.setRequestHeader("Authorization", "Bearer " + token); // req.setRequestHeader("Content-Type", ""); req.onreadystatechange = function() { @@ -41,7 +46,7 @@ function sendBatch(batch: Uint8Array):void { if (this.status == 0) { return; // happens simultaneously with onerror TODO: clear codeflow } - if (this.status >= 400) { + if (this.status >= 400) { // TODO: test workflow. After 400+ it calls /start for some reason reset(); sendQueue.length = 0; if (this.status === 403) { // Unauthorised (Token expired) @@ -69,7 +74,7 @@ function sendBatch(batch: Uint8Array):void { attemptsCount++; setTimeout(() => sendBatch(batch), ATTEMPT_TIMEOUT); } - req.send(batch); + req.send(batch.buffer); } function send(): void { @@ -100,7 +105,7 @@ function hasTimestamp(msg: any): msg is { timestamp: number } { return typeof msg === 'object' && typeof msg.timestamp === 'number'; } -self.onmessage = ({ data }: MessageEvent) => { +self.onmessage = ({ data }: MessageEvent) => { if (data === null) { send(); return; @@ -118,6 +123,7 @@ self.onmessage = ({ data }: MessageEvent) => { timeAdjustment = data.timeAdjustment || timeAdjustment; MAX_ATTEMPTS_COUNT = data.connAttemptCount || MAX_ATTEMPTS_COUNT; ATTEMPT_TIMEOUT = data.connAttemptGap || ATTEMPT_TIMEOUT; + beaconSize = Math.min(BEACON_SIZE_LIMIT, data.beaconSize || beaconSize); if (writer.isEmpty()) { writeBatchMeta(); } @@ -126,7 +132,7 @@ self.onmessage = ({ data }: MessageEvent) => { } return; } - data.forEach((data: any) => { + data.forEach((data) => { const message: Message = new (classes.get(data._id))(); Object.assign(message, data); @@ -140,20 +146,26 @@ self.onmessage = ({ data }: MessageEvent) => { } } - writer.checkpoint(); - nextIndex++; - if (message.encode(writer)) { - isEmpty = false; - } else { + writer.checkpoint(); // TODO: incapsulate in writer + if (!message.encode(writer)) { send(); - if (message.encode(writer)) { - isEmpty = false; - } else { - // MAX_BATCH_SIZE overflow by one message - // TODO: correct handle - nextIndex--; - return; - } + // writer.reset(); // TODO: sematically clear code + if (!message.encode(writer)) { // Try to encode within empty state + // MBTODO: tempWriter for one message? + while (!message.encode(writer)) { + if (beaconSize === BEACON_SIZE_LIMIT) { + console.warn("OpenReplay: beacon size overflow."); + writer.reset(); + writeBatchMeta(); + return + } + beaconSize = Math.min(beaconSize*2, BEACON_SIZE_LIMIT); + writer = new Writer(beaconSize); + writeBatchMeta(); + } + } }; + nextIndex++; // TODO: incapsulate in writer + isEmpty = false; }); }; diff --git a/tracker/tracker/src/webworker/transformer.js b/tracker/tracker/src/webworker/transformer.js deleted file mode 100644 index cf80d681b..000000000 --- a/tracker/tracker/src/webworker/transformer.js +++ /dev/null @@ -1,21 +0,0 @@ -import Message from '../messages/message'; - - - - -class MessageTransformer { - private urlRewriter?: URLRewriter - - constructor() { - - } - - transform(m: Message): Message { - if (m instanceof SetNodeAttribute) { - if (m.name == "src" || m.name == "href") { - sendAssetForCache - } - } - } - -} \ No newline at end of file