From bd41225e46c3d6d3f4dff1a2c76b8d19a92e6bea Mon Sep 17 00:00:00 2001 From: Thanh Dodeur Date: Mon, 6 Sep 2021 09:42:26 +0000 Subject: [PATCH] [FIX] mail: cleanup onbeforeunload and rpc button locks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commits adds a proper event listener removal for `onbeforeunload` to facilitate testing and cleans up the join/leave rpc button locking. closes odoo/odoo#76327 X-original-commit: 28d4c80b0dd2f30fb6aab46099a3c64d18f8d3b9 Signed-off-by: Sébastien Theys (seb) --- .../chat_window_header/chat_window_header.js | 6 ++++ .../rtc_invitation_card.js | 6 ++++ .../thread_view_topbar/thread_view_topbar.js | 6 ++++ addons/mail/static/src/models/rtc/rtc.js | 17 +++++++-- .../models/rtc_controller/rtc_controller.js | 9 +++++ .../mail/static/src/models/thread/thread.js | 35 ++++++++----------- 6 files changed, 55 insertions(+), 24 deletions(-) diff --git a/addons/mail/static/src/components/chat_window_header/chat_window_header.js b/addons/mail/static/src/components/chat_window_header/chat_window_header.js index b6354b7c066..3fc64219274 100644 --- a/addons/mail/static/src/components/chat_window_header/chat_window_header.js +++ b/addons/mail/static/src/components/chat_window_header/chat_window_header.js @@ -80,6 +80,9 @@ export class ChatWindowHeader extends Component { */ async _onClickCamera(ev) { ev.stopPropagation(); + if (this.chatWindow.thread.hasPendingRtcRequest) { + return; + } await this.chatWindow.thread.toggleCall({ startWithVideo: true }); } @@ -89,6 +92,9 @@ export class ChatWindowHeader extends Component { */ async _onClickPhone(ev) { ev.stopPropagation(); + if (this.chatWindow.thread.hasPendingRtcRequest) { + return; + } await this.chatWindow.thread.toggleCall(); } diff --git a/addons/mail/static/src/components/rtc_invitation_card/rtc_invitation_card.js b/addons/mail/static/src/components/rtc_invitation_card/rtc_invitation_card.js index 0a1b8ed44ac..2672a0d0b61 100644 --- a/addons/mail/static/src/components/rtc_invitation_card/rtc_invitation_card.js +++ b/addons/mail/static/src/components/rtc_invitation_card/rtc_invitation_card.js @@ -27,6 +27,9 @@ export class RtcInvitationCard extends Component { */ async _onClickAccept(ev) { this.thread.open(); + if (this.thread.hasPendingRtcRequest) { + return; + } await this.thread.toggleCall(); } @@ -43,6 +46,9 @@ export class RtcInvitationCard extends Component { * @param {MouseEvent} ev */ _onClickRefuse(ev) { + if (this.thread.hasPendingRtcRequest) { + return; + } this.thread.leaveCall(); } diff --git a/addons/mail/static/src/components/thread_view_topbar/thread_view_topbar.js b/addons/mail/static/src/components/thread_view_topbar/thread_view_topbar.js index b3dc357da48..4930ee4df7f 100644 --- a/addons/mail/static/src/components/thread_view_topbar/thread_view_topbar.js +++ b/addons/mail/static/src/components/thread_view_topbar/thread_view_topbar.js @@ -38,6 +38,9 @@ export class ThreadViewTopbar extends Component { * @param {MouseEvent} ev */ async _onClickPhone(ev) { + if (this.threadViewTopBar.thread.hasPendingRtcRequest) { + return; + } await this.threadViewTopBar.thread.toggleCall(); } @@ -46,6 +49,9 @@ export class ThreadViewTopbar extends Component { * @param {MouseEvent} ev */ async _onClickCamera(ev) { + if (this.threadViewTopBar.thread.hasPendingRtcRequest) { + return; + } await this.threadViewTopBar.thread.toggleCall({ startWithVideo: true, }); diff --git a/addons/mail/static/src/models/rtc/rtc.js b/addons/mail/static/src/models/rtc/rtc.js index ea0cadc0995..bb6306510f1 100644 --- a/addons/mail/static/src/models/rtc/rtc.js +++ b/addons/mail/static/src/models/rtc/rtc.js @@ -74,9 +74,9 @@ function factory(dependencies) { this._onKeyUp = this._onKeyUp.bind(this); browser.addEventListener('keydown', this._onKeyDown); browser.addEventListener('keyup', this._onKeyUp); - browser.addEventListener('beforeunload', async () => { - this.channel && await this.channel.leaveCall(); - }); + // Disconnects the RTC session if the page is closed or reloaded. + this._onBeforeUnload = this._onBeforeUnload.bind(this); + browser.addEventListener('beforeunload', this._onBeforeUnload); /** * Call all sessions for which no peerConnection is established at * a regular interval to try to recover any connection that failed @@ -94,6 +94,7 @@ function factory(dependencies) { * @override */ async _willDelete() { + browser.removeEventListener('beforeunload', this._onBeforeUnload); browser.removeEventListener('keydown', this._onKeyDown); browser.removeEventListener('keyup', this._onKeyUp); return super._willDelete(...arguments); @@ -975,6 +976,16 @@ function factory(dependencies) { // Handlers //---------------------------------------------------------------------- + /** + * @private + * @param {Event} ev + */ + async _onBeforeUnload(ev) { + if (this.channel) { + await this.channel.performRpcLeaveCall(); + } + } + /** * @private * @param {String} state the new state of the connection diff --git a/addons/mail/static/src/models/rtc_controller/rtc_controller.js b/addons/mail/static/src/models/rtc_controller/rtc_controller.js index 163484a8d60..053c34b94c0 100644 --- a/addons/mail/static/src/models/rtc_controller/rtc_controller.js +++ b/addons/mail/static/src/models/rtc_controller/rtc_controller.js @@ -51,6 +51,9 @@ function factory(dependencies) { * @param {MouseEvent} ev */ async onClickRejectCall(ev) { + if (this.callViewer.threadView.thread.hasPendingRtcRequest) { + return; + } await this.callViewer.threadView.thread.leaveCall(); } @@ -65,6 +68,9 @@ function factory(dependencies) { * @param {MouseEvent} ev */ async onClickToggleAudioCall(ev) { + if (this.callViewer.threadView.thread.hasPendingRtcRequest) { + return; + } await this.callViewer.threadView.thread.toggleCall(); } @@ -72,6 +78,9 @@ function factory(dependencies) { * @param {MouseEvent} ev */ async onClickToggleVideoCall(ev) { + if (this.callViewer.threadView.thread.hasPendingRtcRequest) { + return; + } await this.callViewer.threadView.thread.toggleCall({ startWithVideo: true, }); diff --git a/addons/mail/static/src/models/thread/thread.js b/addons/mail/static/src/models/thread/thread.js index e5789ee9079..135c1026427 100644 --- a/addons/mail/static/src/models/thread/thread.js +++ b/addons/mail/static/src/models/thread/thread.js @@ -574,6 +574,16 @@ function factory(dependencies) { ); } + /** + * Performs the rpc to leave the rtc call of the channel. + */ + async performRpcLeaveCall() { + await this.async(() => this.env.services.rpc({ + route: '/mail/rtc/channel/leave_call', + params: { channel_id: this.id }, + }, { shadow: true })); + } + /** * Performs RPC on the route `/mail/get_suggested_recipients`. * @@ -731,14 +741,17 @@ function factory(dependencies) { * @param {Object} options */ async toggleCall(options) { + this.update({ hasPendingRtcRequest: true }); const isActiveCall = !!this.mailRtc; if (this.messaging.mailRtc.channel) { await this.messaging.mailRtc.channel.leaveCall(); } if (isActiveCall) { + this.update({ hasPendingRtcRequest: false }); return; } await this._joinCall(options); + this.update({ hasPendingRtcRequest: false }); } /** @@ -757,10 +770,6 @@ function factory(dependencies) { }); return; } - if (this.hasPendingRtcRequest) { - return; - } - this.update({ hasPendingRtcRequest: true }); const { rtcSessions, iceServers, sessionId, invitedPartners, invitedGuests } = await this.async(() => this.env.services.rpc({ route: '/mail/rtc/channel/join_call', params: { @@ -768,7 +777,6 @@ function factory(dependencies) { }, }, { shadow: true })); this.update({ - hasPendingRtcRequest: false, mailRtc: link(this.messaging.mailRtc), rtcInvitingSession: unlink(), rtcSessions: insertAndReplace(rtcSessions.map(record => this.messaging.models['mail.rtc_session'].convertData(record))), @@ -789,10 +797,7 @@ function factory(dependencies) { * Notifies the server and does the cleanup of the current call. */ async leaveCall() { - if (this.hasPendingRtcRequest) { - return; - } - await this._leaveCall(); + await this.performRpcLeaveCall(); this.endCall(); } @@ -1821,18 +1826,6 @@ function factory(dependencies) { } } - /** - * @private - */ - async _leaveCall() { - this.update({ hasPendingRtcRequest: true }); - await this.async(() => this.env.services.rpc({ - route: '/mail/rtc/channel/leave_call', - params: { channel_id: this.id }, - }, { shadow: true })); - this.update({ hasPendingRtcRequest: false }); - } - /** * Handles change of fold state coming from the server. Useful to * synchronize corresponding chat window.