From 3413fc7a7e6f8fc32c9d7feae26a1658bc071251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Tue, 15 Aug 2023 01:24:43 +0200 Subject: [PATCH 1/2] Extract method to process "token_expired" errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- src/utils/signaling.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/utils/signaling.js b/src/utils/signaling.js index 05ae19100e4..67f53195104 100644 --- a/src/utils/signaling.js +++ b/src/utils/signaling.js @@ -772,8 +772,7 @@ Signaling.Standalone.prototype.connect = function() { console.error('An error occurred processing the signaling message, please ask your server administrator to check the log file') break case 'token_expired': - console.info('The signaling token is expired, need to update settings') - this._trigger('updateSettings') + this.processErrorTokenExpired() break default: console.error('Ignore unknown error', data) @@ -1421,6 +1420,12 @@ Signaling.Standalone.prototype.processRoomParticipantsEvent = function(data) { } } +Signaling.Standalone.prototype.processErrorTokenExpired = function() { + console.info('The signaling token is expired, need to update settings') + + this._trigger('updateSettings') +} + Signaling.Standalone.prototype.requestOffer = function(sessionid, roomType, sid = undefined) { if (!this.hasFeature('mcu')) { console.warn("Can't request an offer without a MCU.") From 510f569c73c9b010b7fd2b07068b2623b48a6c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Fri, 2 Dec 2022 21:13:55 +0100 Subject: [PATCH 2/2] Fix using signaling settings while being refetched MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the external signaling server returns the error "token_expired" the signaling settings are fetched again. However, if there are further requests and "token_expired" is returned again the previous fetch is canceled and a new one started instead, which caused the settings to be temporary set to "null". The signaling settings are expected to always be an object, so setting them to "null" could cause an error if they were used during that time (for example, during a reconnection, which caused the signaling object to "hang" and not do any further connection attempt). Preventing the settings to be nullified is only half of the story, though; "token_expired" can be thrown when trying to connect, and errors thrown when trying to connect cause a reconnection attempt. This could end in a reconnection loop, as each "token_expired" error would cause another fetch of the settings, cancelling the previous fetch and thus preventing the settings to be updated, and as the previous settings would be still used any connection attempt would end again in another "token_expired" error. To solve all that now any connection attempt done after receiving a "token_expired" error is deferred until the signaling settings were updated. Note that the previous signaling settings are kept to ensure that a signaling object is always available, even if outdated. However, any usage of the outdated signaling settings is expected to cause a "token_expired" error to be thrown; right now that only happens during connections, so only that code needs to wait for the settings to be fetched again. Signed-off-by: Daniel Calviño Sánchez --- src/utils/signaling.js | 38 ++++++++++++++++++++++++++++++++++++++ src/utils/webrtc/index.js | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/utils/signaling.js b/src/utils/signaling.js index 67f53195104..31fce365f83 100644 --- a/src/utils/signaling.js +++ b/src/utils/signaling.js @@ -141,6 +141,20 @@ Signaling.Base.prototype._trigger = function(ev, args) { EventBus.$emit('signaling-' + kebabCase(ev), args) } +Signaling.Base.prototype.setSettings = function(settings) { + if (!settings) { + // Signaling object is expected to always have a settings object + return + } + + this.settings = settings + + if (this._pendingUpdateSettingsPromise) { + this._pendingUpdateSettingsPromise.resolve() + delete this._pendingUpdateSettingsPromise + } +} + Signaling.Base.prototype.isNoMcuWarningEnabled = function() { return !this.settings.hideWarning } @@ -654,6 +668,19 @@ Signaling.Standalone.prototype.connect = function() { }, 2000) } + if (this._pendingUpdateSettingsPromise) { + console.info('Deferring establishing signaling connection until signaling settings are updated') + + this._pendingUpdateSettingsPromise.then(() => { + // "reconnect()" is called instead of "connect()", even if that + // slightly delays the connection, as "reconnect()" prevents + // duplicated connection requests. + this.reconnect() + }) + + return + } + console.debug('Connecting to ' + this.url + ' for ' + this.settings.token) this.callbacks = {} this.id = 1 @@ -1423,6 +1450,17 @@ Signaling.Standalone.prototype.processRoomParticipantsEvent = function(data) { Signaling.Standalone.prototype.processErrorTokenExpired = function() { console.info('The signaling token is expired, need to update settings') + if (!this._pendingUpdateSettingsPromise) { + let pendingUpdateSettingsPromiseResolve + this._pendingUpdateSettingsPromise = new Promise((resolve, reject) => { + // The Promise executor is run even before the Promise constructor has + // finished, so "this._pendingUpdateSettingsPromise" is not available + // yet. + pendingUpdateSettingsPromiseResolve = resolve + }) + this._pendingUpdateSettingsPromise.resolve = pendingUpdateSettingsPromiseResolve + } + this._trigger('updateSettings') } diff --git a/src/utils/webrtc/index.js b/src/utils/webrtc/index.js index dc3d019619c..020b201a046 100644 --- a/src/utils/webrtc/index.js +++ b/src/utils/webrtc/index.js @@ -123,7 +123,7 @@ async function connectSignaling(token) { signaling.on('updateSettings', async function() { const settings = await getSignalingSettings(token) console.debug('Received updated settings', settings) - signaling.settings = settings + signaling.setSettings(settings) }) }