From b9b038e3528e6c1a0324d82c5efa27d2f76c1b24 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 f2ff002822d..8742b6a7761 100644 --- a/src/utils/signaling.js +++ b/src/utils/signaling.js @@ -776,8 +776,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) @@ -1439,6 +1438,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 f5ec396f383a31dfc889d7bf22ac4f46079dd51f 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 8742b6a7761..2b6cea10c31 100644 --- a/src/utils/signaling.js +++ b/src/utils/signaling.js @@ -143,6 +143,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 } @@ -658,6 +672,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 @@ -1441,6 +1468,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 ed40d355c77..3c69decbd87 100644 --- a/src/utils/webrtc/index.js +++ b/src/utils/webrtc/index.js @@ -134,7 +134,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) }) signalingTypingHandler?.setSignaling(signaling)