From 8eab9ab28b33884da9ba0d18a3b18e848056e55c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 23 Aug 2021 15:54:40 +0200 Subject: [PATCH] add 2s timeout on input of homeserver to also query the homeserver, in addition to change event --- src/domain/login/LoginViewModel.js | 84 +++++++++++++++++--------- src/platform/web/ui/login/LoginView.js | 7 ++- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/src/domain/login/LoginViewModel.js b/src/domain/login/LoginViewModel.js index 85dddb79..8827a511 100644 --- a/src/domain/login/LoginViewModel.js +++ b/src/domain/login/LoginViewModel.js @@ -39,8 +39,9 @@ export class LoginViewModel extends ViewModel { this._errorMessage = ""; this._hideHomeserver = false; this._isBusy = false; - this._isFetchingLoginOptions = false; - this._createViewModels(this._homeserver); + this._abortHomeserverQueryTimeout = null; + this._abortQueryOperation = null; + this._initViewModels(); } get passwordLoginViewModel() { return this._passwordLoginViewModel; } @@ -51,13 +52,13 @@ export class LoginViewModel extends ViewModel { get showHomeserver() { return !this._hideHomeserver; } get loadViewModel() {return this._loadViewModel; } get isBusy() { return this._isBusy; } - get isFetchingLoginOptions() { return this._isFetchingLoginOptions; } + get isFetchingLoginOptions() { return !!this._abortQueryOperation; } goBack() { this.navigation.push("session"); } - async _createViewModels(homeserver) { + async _initViewModels() { if (this._loginToken) { this._hideHomeserver = true; this._completeSSOLoginViewModel = this.track(new CompleteSSOLoginViewModel( @@ -70,27 +71,7 @@ export class LoginViewModel extends ViewModel { this.emitChange("completeSSOLoginViewModel"); } else { - this._errorMessage = ""; - try { - this._isFetchingLoginOptions = true; - this.emitChange("isFetchingLoginOptions"); - this._loginOptions = await this._sessionContainer.queryLogin(homeserver); - } - catch (e) { - this._loginOptions = null; - } - this._isFetchingLoginOptions = false; - this.emitChange("isFetchingLoginOptions"); - if (this._loginOptions) { - if (this._loginOptions.sso) { this._showSSOLogin(); } - if (this._loginOptions.password) { this._showPasswordLogin(); } - if (!this._loginOptions.sso && !this._loginOptions.password) { - this._showError("This homeserver neither supports SSO nor Password based login flows"); - } - } - else { - this._showError("Could not query login methods supported by the homeserver"); - } + await this.queryHomeServer(); } } @@ -175,12 +156,59 @@ export class LoginViewModel extends ViewModel { this.emitChange("disposeViewModels"); } - updateHomeServer(newHomeserver) { + async setHomeServerInput(newHomeserver) { + this._homeserver = newHomeserver; + // abort ongoing query, if any + this._abortQueryOperation = this.disposeTracked(this._abortQueryOperation); + this.emitChange("isFetchingLoginOptions"); + this.disposeTracked(this._abortHomeserverQueryTimeout); + const timeout = this.clock.createTimeout(2000); + this._abortHomeserverQueryTimeout = this.track(() => timeout.abort()); + try { + await timeout.elapsed(); + } catch (err) { + if (err.name === "AbortError") { + return; // still typing, don't query + } else { + throw err; + } + } + this._abortHomeserverQueryTimeout = this.disposeTracked(this._abortHomeserverQueryTimeout); + this.queryHomeServer(); + } + + async queryHomeServer() { this._errorMessage = ""; this.emitChange("errorMessage"); - this._homeserver = newHomeserver; + this._abortQueryOperation = this.disposeTracked(this._abortQueryOperation); this._disposeViewModels(); - this._createViewModels(newHomeserver); + try { + const queryOperation = this._sessionContainer.queryLogin(this._homeserver); + this._abortQueryOperation = this.track(() => queryOperation.abort()); + this.emitChange("isFetchingLoginOptions"); + this._loginOptions = await queryOperation.result; + } + catch (e) { + console.log("error", e); + if (e.name === "AbortError") { + return; //aborted, bail out + } else { + this._loginOptions = null; + } + } finally { + this._abortQueryOperation = this.disposeTracked(this._abortQueryOperation); + this.emitChange("isFetchingLoginOptions"); + } + if (this._loginOptions) { + if (this._loginOptions.sso) { this._showSSOLogin(); } + if (this._loginOptions.password) { this._showPasswordLogin(); } + if (!this._loginOptions.sso && !this._loginOptions.password) { + this._showError("This homeserver supports neither SSO nor password based login flows"); + } + } + else { + this._showError("Could not query login methods supported by the homeserver"); + } } dispose() { diff --git a/src/platform/web/ui/login/LoginView.js b/src/platform/web/ui/login/LoginView.js index 3d8e8470..df92cb67 100644 --- a/src/platform/web/ui/login/LoginView.js +++ b/src/platform/web/ui/login/LoginView.js @@ -36,7 +36,6 @@ export class LoginView extends TemplateView { t.mapView(vm => vm.completeSSOLoginViewModel, vm => vm ? new CompleteSSOView(vm) : null), t.if(vm => vm.showHomeserver, (t, vm) => t.div({ className: "LoginView_sso form form-row" }, [ - t.if(vm => vm.errorMessage, (t, vm) => t.p({className: "error"}, vm.i18n(vm.errorMessage))), t.label({for: "homeserver"}, vm.i18n`Homeserver`), t.input({ id: "homeserver", @@ -44,8 +43,10 @@ export class LoginView extends TemplateView { placeholder: vm.i18n`Your matrix homeserver`, value: vm.homeserver, disabled, - onChange: event => vm.updateHomeServer(event.target.value), - }) + onInput: () => vm.setHomeServerInput(event.target.value), + onChange: event => vm.queryHomeServer(), + }), + t.if(vm => vm.errorMessage, (t, vm) => t.p({className: "error"}, vm.i18n(vm.errorMessage))), ] )), t.if(vm => vm.isFetchingLoginOptions, t => t.div({className: "LoginView_query-spinner"}, [spinner(t), t.p("Fetching available login options...")])),