From b88a6440af977c250773ce2adba225f5e175dec0 Mon Sep 17 00:00:00 2001 From: Philzen Date: Wed, 18 Dec 2024 06:19:27 +0100 Subject: [PATCH 1/5] Implement Proxy to intercept & modify `disconnectOnPageLeave` behavior --- src/room/Room.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/room/Room.ts b/src/room/Room.ts index 4446fda35c..69c7803f02 100644 --- a/src/room/Room.ts +++ b/src/room/Room.ts @@ -234,6 +234,19 @@ class Room extends (EventEmitter as new () => TypedEmitter) if (this.options.e2ee) { this.setupE2EE(); } + + const self = this + this.options = new Proxy(this.options, { + set: function (target: InternalRoomOptions, key: keyof InternalRoomOptions, value) { + if (key == 'disconnectOnPageLeave' && value !== target[key]) { + value === true + ? window.addEventListener('beforeunload', self.onPageLeave) + : window.removeEventListener('beforeunload', self.onPageLeave) + } + + return true; + } + }) } /** From 14a59e9676db70b2dbe6584d320364720db92e03 Mon Sep 17 00:00:00 2001 From: Philzen Date: Wed, 18 Dec 2024 19:24:53 +0100 Subject: [PATCH 2/5] Remove duplication, allow lexical context, fix default setter behavior Also only call `removeEventListener` in handleDisconnect() when actually registered before. --- src/room/Room.ts | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/room/Room.ts b/src/room/Room.ts index 69c7803f02..37f6a4d33e 100644 --- a/src/room/Room.ts +++ b/src/room/Room.ts @@ -235,15 +235,15 @@ class Room extends (EventEmitter as new () => TypedEmitter) this.setupE2EE(); } - const self = this this.options = new Proxy(this.options, { - set: function (target: InternalRoomOptions, key: keyof InternalRoomOptions, value) { + set: (target: InternalRoomOptions, key: keyof InternalRoomOptions, value) => { + console.log("Proxy is intercepting!", key, value) if (key == 'disconnectOnPageLeave' && value !== target[key]) { - value === true - ? window.addEventListener('beforeunload', self.onPageLeave) - : window.removeEventListener('beforeunload', self.onPageLeave) + value === true ? this.registerUnloadEvents() : this.unregisterUnloadEvents() } - + + (target[key] as any) = value + return true; } }) @@ -774,13 +774,8 @@ class Room extends (EventEmitter as new () => TypedEmitter) throw e; } - // also hook unload event - if (isWeb() && this.options.disconnectOnPageLeave) { - // capturing both 'pagehide' and 'beforeunload' to capture broadest set of browser behaviors - window.addEventListener('pagehide', this.onPageLeave); - window.addEventListener('beforeunload', this.onPageLeave); - } if (isWeb()) { + this.options.disconnectOnPageLeave && this.registerUnloadEvents() document.addEventListener('freeze', this.onPageLeave); navigator.mediaDevices?.addEventListener('devicechange', this.handleDeviceChange); } @@ -971,6 +966,23 @@ class Room extends (EventEmitter as new () => TypedEmitter) } } + /** + * Add listeners for 'pagehide' and 'beforeunload' events (capturing broadest set of browser behaviors) + * to handle disconnect and cleanup + */ + private registerUnloadEvents = () => { + window.addEventListener('pagehide', this.onPageLeave); + window.addEventListener('beforeunload', this.onPageLeave); + } + + /** + * Remove listeners for 'pagehide' and 'beforeunload' which would handle disconnect and cleanup + */ + private unregisterUnloadEvents = () => { + window.removeEventListener('beforeunload', this.onPageLeave); + window.removeEventListener('pagehide', this.onPageLeave); + } + private onPageLeave = async () => { this.log.info('Page leave detected, disconnecting', this.logContext); await this.disconnect(); @@ -1398,8 +1410,7 @@ class Room extends (EventEmitter as new () => TypedEmitter) this.audioContext = undefined; } if (isWeb()) { - window.removeEventListener('beforeunload', this.onPageLeave); - window.removeEventListener('pagehide', this.onPageLeave); + this.options.disconnectOnPageLeave && this.unregisterUnloadEvents() window.removeEventListener('freeze', this.onPageLeave); navigator.mediaDevices?.removeEventListener('devicechange', this.handleDeviceChange); } From f75f4c45323f92b4ae3f67f71c603a58576c1bff Mon Sep 17 00:00:00 2001 From: Philzen Date: Wed, 18 Dec 2024 20:11:16 +0100 Subject: [PATCH 3/5] Remove console.log and add comment to Proxy --- src/room/Room.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/room/Room.ts b/src/room/Room.ts index 37f6a4d33e..ad3da8cb25 100644 --- a/src/room/Room.ts +++ b/src/room/Room.ts @@ -235,9 +235,11 @@ class Room extends (EventEmitter as new () => TypedEmitter) this.setupE2EE(); } + /** + * Proxy for interception of changes to InternalRoomOptions after Room has been instantiated. + */ this.options = new Proxy(this.options, { set: (target: InternalRoomOptions, key: keyof InternalRoomOptions, value) => { - console.log("Proxy is intercepting!", key, value) if (key == 'disconnectOnPageLeave' && value !== target[key]) { value === true ? this.registerUnloadEvents() : this.unregisterUnloadEvents() } From a40187a70ada7e385e58d509baa99f30bb59c95b Mon Sep 17 00:00:00 2001 From: Philzen Date: Sun, 29 Dec 2024 15:58:16 +0100 Subject: [PATCH 4/5] Replace shorter tenary expression with if-statements This is required to adhere to @typescript-eslint/no-unused-expressions --- src/room/Room.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/room/Room.ts b/src/room/Room.ts index ad3da8cb25..7044112c07 100644 --- a/src/room/Room.ts +++ b/src/room/Room.ts @@ -241,7 +241,11 @@ class Room extends (EventEmitter as new () => TypedEmitter) this.options = new Proxy(this.options, { set: (target: InternalRoomOptions, key: keyof InternalRoomOptions, value) => { if (key == 'disconnectOnPageLeave' && value !== target[key]) { - value === true ? this.registerUnloadEvents() : this.unregisterUnloadEvents() + if (value === true) { + this.registerUnloadEvents() + } else { + this.unregisterUnloadEvents() + } } (target[key] as any) = value @@ -777,7 +781,9 @@ class Room extends (EventEmitter as new () => TypedEmitter) } if (isWeb()) { - this.options.disconnectOnPageLeave && this.registerUnloadEvents() + if (this.options.disconnectOnPageLeave) { + this.registerUnloadEvents() + } document.addEventListener('freeze', this.onPageLeave); navigator.mediaDevices?.addEventListener('devicechange', this.handleDeviceChange); } @@ -1412,7 +1418,9 @@ class Room extends (EventEmitter as new () => TypedEmitter) this.audioContext = undefined; } if (isWeb()) { - this.options.disconnectOnPageLeave && this.unregisterUnloadEvents() + if (this.options.disconnectOnPageLeave) { + this.unregisterUnloadEvents() + } window.removeEventListener('freeze', this.onPageLeave); navigator.mediaDevices?.removeEventListener('devicechange', this.handleDeviceChange); } From fd19953f51927ec886bf57864ba6a37a40529660 Mon Sep 17 00:00:00 2001 From: Philzen Date: Sun, 29 Dec 2024 16:39:33 +0100 Subject: [PATCH 5/5] Run prettier with --write option to add commas & semicolons --- src/room/Room.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/room/Room.ts b/src/room/Room.ts index 7044112c07..a104eed510 100644 --- a/src/room/Room.ts +++ b/src/room/Room.ts @@ -242,17 +242,17 @@ class Room extends (EventEmitter as new () => TypedEmitter) set: (target: InternalRoomOptions, key: keyof InternalRoomOptions, value) => { if (key == 'disconnectOnPageLeave' && value !== target[key]) { if (value === true) { - this.registerUnloadEvents() + this.registerUnloadEvents(); } else { - this.unregisterUnloadEvents() + this.unregisterUnloadEvents(); } } - (target[key] as any) = value + (target[key] as any) = value; return true; - } - }) + }, + }); } /** @@ -782,7 +782,7 @@ class Room extends (EventEmitter as new () => TypedEmitter) if (isWeb()) { if (this.options.disconnectOnPageLeave) { - this.registerUnloadEvents() + this.registerUnloadEvents(); } document.addEventListener('freeze', this.onPageLeave); navigator.mediaDevices?.addEventListener('devicechange', this.handleDeviceChange); @@ -981,7 +981,7 @@ class Room extends (EventEmitter as new () => TypedEmitter) private registerUnloadEvents = () => { window.addEventListener('pagehide', this.onPageLeave); window.addEventListener('beforeunload', this.onPageLeave); - } + }; /** * Remove listeners for 'pagehide' and 'beforeunload' which would handle disconnect and cleanup @@ -989,7 +989,7 @@ class Room extends (EventEmitter as new () => TypedEmitter) private unregisterUnloadEvents = () => { window.removeEventListener('beforeunload', this.onPageLeave); window.removeEventListener('pagehide', this.onPageLeave); - } + }; private onPageLeave = async () => { this.log.info('Page leave detected, disconnecting', this.logContext); @@ -1419,7 +1419,7 @@ class Room extends (EventEmitter as new () => TypedEmitter) } if (isWeb()) { if (this.options.disconnectOnPageLeave) { - this.unregisterUnloadEvents() + this.unregisterUnloadEvents(); } window.removeEventListener('freeze', this.onPageLeave); navigator.mediaDevices?.removeEventListener('devicechange', this.handleDeviceChange);