From bb09e7f2ed72d6f936e72e3722d10aba0b0cd77c Mon Sep 17 00:00:00 2001 From: Alex Kaminskii Date: Mon, 10 Oct 2022 12:34:48 +0200 Subject: [PATCH] refactor(tracker): WebWorker interactions typification --- tracker/tracker/src/common/interaction.ts | 9 +++++- tracker/tracker/src/main/app/index.ts | 32 ++++++++++++-------- tracker/tracker/src/webworker/QueueSender.ts | 4 +-- tracker/tracker/src/webworker/index.ts | 16 +++++----- 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/tracker/tracker/src/common/interaction.ts b/tracker/tracker/src/common/interaction.ts index 19d8fa906..0720bf2a8 100644 --- a/tracker/tracker/src/common/interaction.ts +++ b/tracker/tracker/src/common/interaction.ts @@ -19,4 +19,11 @@ type Auth = { beaconSizeLimit?: number } -export type WorkerMessageData = null | 'stop' | Start | Auth | Array +export type ToWorkerData = null | 'stop' | Start | Auth | Array + +type Failure = { + type: 'failure' + reason: string +} + +export type FromWorkerData = 'restart' | Failure diff --git a/tracker/tracker/src/main/app/index.ts b/tracker/tracker/src/main/app/index.ts index e52cd2dc2..95ddd83d0 100644 --- a/tracker/tracker/src/main/app/index.ts +++ b/tracker/tracker/src/main/app/index.ts @@ -14,7 +14,15 @@ 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 SessOptions } from './session.js' -import type { Options as WebworkerOptions, WorkerMessageData } from '../../common/interaction.js' +import type { + Options as WebworkerOptions, + ToWorkerData, + FromWorkerData, +} from '../../common/interaction.js' + +interface TypedWorker extends Omit { + postMessage(data: ToWorkerData): void +} // TODO: Unify and clearly describe options logic export interface StartOptions { @@ -94,7 +102,7 @@ export default class App { private readonly revID: string private activityState: ActivityState = ActivityState.NotActive private readonly version = 'TRACKER_VERSION' // TODO: version compatability check inside each plugin. - private readonly worker?: Worker + private readonly worker?: TypedWorker constructor(projectKey: string, sessionToken: string | undefined, options: Partial) { // if (options.onStart !== undefined) { // deprecationWarn("'onStart' option", "tracker.start().then(/* handle session info */)") @@ -153,13 +161,13 @@ export default class App { this.worker.onerror = (e) => { this._debug('webworker_error', e) } - this.worker.onmessage = ({ data }: MessageEvent) => { - if (data === 'failed') { - this.stop(false) - this._debug('worker_failed', {}) // add context (from worker) - } else if (data === 'restart') { + this.worker.onmessage = ({ data }: MessageEvent) => { + if (data === 'restart') { this.stop(false) this.start({ forceNew: true }) // TODO: keep userID & metadata (draw scenarios) + } else if (data.type === 'failure') { + this.stop(false) + this._debug('worker_failed', data.reason) } } const alertWorker = () => { @@ -372,7 +380,7 @@ export default class App { } const timestamp = now() - const startWorkerMsg: WorkerMessageData = { + this.worker.postMessage({ type: 'start', pageNo: this.session.incPageNo(), ingestPoint: this.options.ingestPoint, @@ -380,8 +388,7 @@ export default class App { url: document.URL, connAttemptCount: this.options.connAttemptCount, connAttemptGap: this.options.connAttemptGap, - } - this.worker.postMessage(startWorkerMsg) + }) this.session.update({ // TODO: transparent "session" module logic AND explicit internal api for plugins. @@ -455,12 +462,11 @@ export default class App { this.session.update({ sessionID, timestamp: startTimestamp || timestamp, projectID }) // TODO: no no-explicit 'any' this.localStorage.setItem(this.options.local_uuid_key, userUUID) - const startWorkerMsg: WorkerMessageData = { + this.worker.postMessage({ type: 'auth', token, beaconSizeLimit, - } - this.worker.postMessage(startWorkerMsg) + }) const onStartInfo = { sessionToken: token, userUUID, sessionID } diff --git a/tracker/tracker/src/webworker/QueueSender.ts b/tracker/tracker/src/webworker/QueueSender.ts index 6082e222b..aa1ff4589 100644 --- a/tracker/tracker/src/webworker/QueueSender.ts +++ b/tracker/tracker/src/webworker/QueueSender.ts @@ -29,7 +29,7 @@ export default class QueueSender { constructor( ingestBaseURL: string, private readonly onUnauthorised: () => any, - private readonly onFailure: () => any, + private readonly onFailure: (reason: string) => any, private readonly MAX_ATTEMPTS_COUNT = 10, private readonly ATTEMPT_TIMEOUT = 1000, ) { @@ -50,7 +50,7 @@ export default class QueueSender { private retry(batch: Uint8Array): void { if (this.attemptsCount >= this.MAX_ATTEMPTS_COUNT) { - this.onFailure() + this.onFailure(`Failed to send batch after ${this.attemptsCount} attempts.`) return } this.attemptsCount++ diff --git a/tracker/tracker/src/webworker/index.ts b/tracker/tracker/src/webworker/index.ts index 4faaf1395..6cddb8a6b 100644 --- a/tracker/tracker/src/webworker/index.ts +++ b/tracker/tracker/src/webworker/index.ts @@ -1,10 +1,12 @@ import type Message from '../common/messages.gen.js' import { Type as MType } from '../common/messages.gen.js' -import { WorkerMessageData } from '../common/interaction.js' +import { ToWorkerData, FromWorkerData } from '../common/interaction.js' import QueueSender from './QueueSender.js' import BatchWriter from './BatchWriter.js' +declare function postMessage(message: FromWorkerData): void + enum WorkerStatus { NotActive, Starting, @@ -51,18 +53,18 @@ function reset(): void { } function initiateRestart(): void { - self.postMessage('restart') + postMessage('restart') reset() } -function initiateFailure(): void { - self.postMessage('failed') +function initiateFailure(reason: string): void { + postMessage({ type: 'failure', reason }) reset() } let sendIntervalID: ReturnType | null = null let restartTimeoutID: ReturnType -self.onmessage = ({ data }: MessageEvent): any => { +self.onmessage = ({ data }: MessageEvent): any => { if (data == null) { finalize() return @@ -101,9 +103,9 @@ self.onmessage = ({ data }: MessageEvent): any => { // onUnauthorised initiateRestart() }, - () => { + (reason) => { // onFailure - initiateFailure() + initiateFailure(reason) }, data.connAttemptCount, data.connAttemptGap,