diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2019-03-27 15:46:33 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2019-04-01 13:55:12 +0200 |
| commit | c54a8e8af8ed5e53151ded7f66d9eea7cf7a5d20 (patch) | |
| tree | 6a155396bedff004b0f733ad7fc304b8cc215336 /gui/src/renderer | |
| parent | bcf731749bddebb2eb25ccc6a5b83b45de8fdb0e (diff) | |
| download | mullvadvpn-c54a8e8af8ed5e53151ded7f66d9eea7cf7a5d20.tar.xz mullvadvpn-c54a8e8af8ed5e53151ded7f66d9eea7cf7a5d20.zip | |
Fix tests
Diffstat (limited to 'gui/src/renderer')
| -rw-r--r-- | gui/src/renderer/app.tsx | 121 | ||||
| -rw-r--r-- | gui/src/renderer/lib/account-data-cache.ts | 118 | ||||
| -rw-r--r-- | gui/src/renderer/lib/auth-failure.ts | 3 |
3 files changed, 122 insertions, 120 deletions
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index 7d2cd2a69a..54b2743467 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -25,11 +25,11 @@ import { IWindowShapeParameters } from '../main/window-controller'; import { loadTranslations } from '../shared/gettext'; import { IGuiSettingsState } from '../shared/gui-settings-state'; import { IpcRendererEventChannel } from '../shared/ipc-event-channel'; +import AccountDataCache, { AccountFetchRetryAction } from './lib/account-data-cache'; import AccountExpiry from './lib/account-expiry'; import { AccountToken, - IAccountData, ILocation, IRelayList, ISettings, @@ -38,6 +38,8 @@ import { TunnelStateTransition, } from '../shared/daemon-rpc-types'; +type AccountVerification = { status: 'verified' } | { status: 'deferred'; error: Error }; + export default class AppRenderer { private memoryHistory = createMemoryHistory(); private reduxStore = configureStore(this.memoryHistory); @@ -597,120 +599,3 @@ export default class AppRenderer { this.reduxActions.settings.updateAutoStart(autoStart); } } - -type AccountVerification = { status: 'verified' } | { status: 'deferred'; error: Error }; -export enum AccountFetchRetryAction { - stop, - retry, -} -interface IAccountFetchWatcher { - onFinish: () => void; - onError: (error: Error) => AccountFetchRetryAction; -} - -// An account data cache that helps to throttle RPC requests to get_account_data and retain the -// cached value for 1 minute. -export class AccountDataCache { - private currentAccount?: AccountToken; - private expiresAt?: Date; - private fetchAttempt = 0; - private fetchRetryTimeout?: NodeJS.Timeout; - private watchers: IAccountFetchWatcher[] = []; - - constructor( - private fetchHandler: (token: AccountToken) => Promise<IAccountData>, - private updateHandler: (data?: IAccountData) => void, - ) {} - - public fetch(accountToken: AccountToken, watcher?: IAccountFetchWatcher) { - // invalidate cache if account token has changed - if (accountToken !== this.currentAccount) { - this.invalidate(); - this.currentAccount = accountToken; - } - - // Only fetch is value has expired - if (this.isExpired()) { - if (watcher) { - this.watchers.push(watcher); - } - - this.performFetch(accountToken); - } else if (watcher) { - watcher.onFinish(); - } - } - - public invalidate() { - if (this.fetchRetryTimeout) { - clearTimeout(this.fetchRetryTimeout); - this.fetchRetryTimeout = undefined; - this.fetchAttempt = 0; - } - - this.expiresAt = undefined; - this.updateHandler(); - this.notifyWatchers((watcher) => { - watcher.onError(new Error('Cancelled')); - }); - } - - private setValue(value: IAccountData) { - this.expiresAt = new Date(Date.now() + 60 * 1000); // 60s expiration - this.updateHandler(value); - this.notifyWatchers((watcher) => watcher.onFinish()); - } - - private isExpired() { - return !this.expiresAt || this.expiresAt < new Date(); - } - - private async performFetch(accountToken: AccountToken) { - try { - // it's possible for invalidate() to be called or for a fetch for a different account token - // to start before this fetch completes, so checking if the current account token is the one - // used is necessary below. - const accountData = await this.fetchHandler(accountToken); - - if (this.currentAccount === accountToken) { - this.setValue(accountData); - } - } catch (error) { - if (this.currentAccount === accountToken) { - this.handleFetchError(accountToken, error); - } - } - } - - private handleFetchError(accountToken: AccountToken, error: any) { - let shouldRetry = true; - - this.notifyWatchers((watcher) => { - if (watcher.onError(error) === AccountFetchRetryAction.stop) { - shouldRetry = false; - } - }); - - if (shouldRetry) { - this.scheduleRetry(accountToken); - } - } - - private scheduleRetry(accountToken: AccountToken) { - this.fetchAttempt += 1; - - // tslint:disable-next-line - const delay = Math.min(2048, 1 << (this.fetchAttempt + 2)) * 1000; - - log.warn(`Failed to fetch account data. Retrying in ${delay} ms`); - - this.fetchRetryTimeout = global.setTimeout(() => { - this.fetchRetryTimeout = undefined; - this.performFetch(accountToken); - }, delay); - } - - private notifyWatchers(notify: (watcher: IAccountFetchWatcher) => void) { - this.watchers.splice(0).forEach(notify); - } -} diff --git a/gui/src/renderer/lib/account-data-cache.ts b/gui/src/renderer/lib/account-data-cache.ts new file mode 100644 index 0000000000..51154c9792 --- /dev/null +++ b/gui/src/renderer/lib/account-data-cache.ts @@ -0,0 +1,118 @@ +import log from 'electron-log'; +import { AccountToken, IAccountData } from '../../shared/daemon-rpc-types'; + +export enum AccountFetchRetryAction { + stop, + retry, +} +interface IAccountFetchWatcher { + onFinish: () => void; + onError: (error: Error) => AccountFetchRetryAction; +} + +// An account data cache that helps to throttle RPC requests to get_account_data and retain the +// cached value for 1 minute. +export default class AccountDataCache { + private currentAccount?: AccountToken; + private expiresAt?: Date; + private fetchAttempt = 0; + private fetchRetryTimeout?: NodeJS.Timeout; + private watchers: IAccountFetchWatcher[] = []; + + constructor( + private fetchHandler: (token: AccountToken) => Promise<IAccountData>, + private updateHandler: (data?: IAccountData) => void, + ) {} + + public fetch(accountToken: AccountToken, watcher?: IAccountFetchWatcher) { + // invalidate cache if account token has changed + if (accountToken !== this.currentAccount) { + this.invalidate(); + this.currentAccount = accountToken; + } + + // Only fetch is value has expired + if (this.isExpired()) { + if (watcher) { + this.watchers.push(watcher); + } + + this.performFetch(accountToken); + } else if (watcher) { + watcher.onFinish(); + } + } + + public invalidate() { + if (this.fetchRetryTimeout) { + clearTimeout(this.fetchRetryTimeout); + this.fetchRetryTimeout = undefined; + this.fetchAttempt = 0; + } + + this.expiresAt = undefined; + this.updateHandler(); + this.notifyWatchers((watcher) => { + watcher.onError(new Error('Cancelled')); + }); + } + + private setValue(value: IAccountData) { + this.expiresAt = new Date(Date.now() + 60 * 1000); // 60s expiration + this.updateHandler(value); + this.notifyWatchers((watcher) => watcher.onFinish()); + } + + private isExpired() { + return !this.expiresAt || this.expiresAt < new Date(); + } + + private async performFetch(accountToken: AccountToken) { + try { + // it's possible for invalidate() to be called or for a fetch for a different account token + // to start before this fetch completes, so checking if the current account token is the one + // used is necessary below. + const accountData = await this.fetchHandler(accountToken); + + if (this.currentAccount === accountToken) { + this.setValue(accountData); + } + } catch (error) { + if (this.currentAccount === accountToken) { + this.handleFetchError(accountToken, error); + } + } + } + + private handleFetchError(accountToken: AccountToken, error: any) { + let shouldRetry = true; + + this.notifyWatchers((watcher) => { + if (watcher.onError(error) === AccountFetchRetryAction.stop) { + shouldRetry = false; + } + }); + + if (shouldRetry) { + this.scheduleRetry(accountToken); + } + } + + private scheduleRetry(accountToken: AccountToken) { + this.fetchAttempt += 1; + + // tslint:disable-next-line + const delay = Math.min(2048, 1 << (this.fetchAttempt + 2)) * 1000; + + log.warn(`Failed to fetch account data. Retrying in ${delay} ms`); + + this.fetchRetryTimeout = global.setTimeout(() => { + this.fetchRetryTimeout = undefined; + this.performFetch(accountToken); + }, delay); + } + + private notifyWatchers(notify: (watcher: IAccountFetchWatcher) => void) { + this.watchers.splice(0).forEach(notify); + } +} diff --git a/gui/src/renderer/lib/auth-failure.ts b/gui/src/renderer/lib/auth-failure.ts index ae381d5677..6428d0f65a 100644 --- a/gui/src/renderer/lib/auth-failure.ts +++ b/gui/src/renderer/lib/auth-failure.ts @@ -18,8 +18,7 @@ export function parseAuthFailure(rawFailureMessage?: string): IAuthFailure { if (results && results.length === 3) { const kind = parseRawFailureKind(results[1]); - const message = - kind === AuthFailureKind.unknown ? rawFailureMessage : messageForFailureKind(kind); + const message = kind === AuthFailureKind.unknown ? results[2] : messageForFailureKind(kind); return { kind, |
