diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2021-09-02 13:02:18 +0200 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2021-09-06 14:38:27 +0200 |
| commit | 823c4c576344eefbcb20abd6c7362f183f615764 (patch) | |
| tree | 793ff0168ebcde1220977fb2fa57094f3a0a49fe /gui/src | |
| parent | 8de764350aaf998b7305b8167ee1c4121069a576 (diff) | |
| download | mullvadvpn-823c4c576344eefbcb20abd6c7362f183f615764.tar.xz mullvadvpn-823c4c576344eefbcb20abd6c7362f183f615764.zip | |
Improve handling of next state
Diffstat (limited to 'gui/src')
| -rw-r--r-- | gui/src/main/index.ts | 43 | ||||
| -rw-r--r-- | gui/src/renderer/app.tsx | 30 |
2 files changed, 60 insertions, 13 deletions
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts index bdaf33a7c8..8fa09576c7 100644 --- a/gui/src/main/index.ts +++ b/gui/src/main/index.ts @@ -124,6 +124,9 @@ class ApplicationMain { private accountData?: IAccountData = undefined; private accountHistory?: AccountToken = undefined; private tunnelState: TunnelState = { state: 'disconnected' }; + private lastIgnoredTunnelState?: TunnelState; + private ignoreTunnelStatesUntil?: TunnelState['state']; + private ignoreTunnelStateFallbackScheduler = new Scheduler(); private settings: ISettings = { accountToken: undefined, allowLan: false, @@ -620,6 +623,10 @@ class ApplicationMain { // Reset the daemon event listener since it's going to be invalidated on disconnect this.daemonEventListener = undefined; + this.ignoreTunnelStatesUntil = undefined; + this.lastIgnoredTunnelState = undefined; + this.autoConnectFallbackScheduler.cancel(); + if (wasConnected) { this.connectedToDaemon = false; @@ -725,7 +732,28 @@ class ApplicationMain { this.wireguardKeygenEventAutoConnect(); } + private setIgnoreTunnelStatesUntil(state: TunnelState['state']) { + this.ignoreTunnelStatesUntil = state; + this.ignoreTunnelStateFallbackScheduler.schedule(() => { + if (this.lastIgnoredTunnelState) { + this.ignoreTunnelStatesUntil = undefined; + this.setTunnelState(this.lastIgnoredTunnelState); + this.lastIgnoredTunnelState = undefined; + } + }, 3000); + } + private setTunnelState(newState: TunnelState) { + if (this.ignoreTunnelStatesUntil) { + if (this.ignoreTunnelStatesUntil === newState.state) { + this.ignoreTunnelStatesUntil = undefined; + this.lastIgnoredTunnelState = undefined; + } else { + this.lastIgnoredTunnelState = newState; + return; + } + } + this.tunnelState = newState; this.updateTrayIcon(newState, this.settings.blockWhenDisconnected); @@ -1102,9 +1130,18 @@ class ApplicationMain { IpcMainEventChannel.location.handleGet(() => this.daemonRpc.getLocation()); - IpcMainEventChannel.tunnel.handleConnect(() => this.daemonRpc.connectTunnel()); - IpcMainEventChannel.tunnel.handleDisconnect(() => this.daemonRpc.disconnectTunnel()); - IpcMainEventChannel.tunnel.handleReconnect(() => this.daemonRpc.reconnectTunnel()); + IpcMainEventChannel.tunnel.handleConnect(() => { + this.setIgnoreTunnelStatesUntil('connecting'); + return this.daemonRpc.connectTunnel(); + }); + IpcMainEventChannel.tunnel.handleDisconnect(() => { + this.setIgnoreTunnelStatesUntil('disconnecting'); + return this.daemonRpc.disconnectTunnel(); + }); + IpcMainEventChannel.tunnel.handleReconnect(() => { + this.setIgnoreTunnelStatesUntil('connecting'); + return this.daemonRpc.reconnectTunnel(); + }); IpcMainEventChannel.guiSettings.handleSetEnableSystemNotifications((flag: boolean) => { this.guiSettings.enableSystemNotifications = flag; diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx index 41e39b0214..dd8a6543ca 100644 --- a/gui/src/renderer/app.tsx +++ b/gui/src/renderer/app.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { Provider } from 'react-redux'; +import { batch, Provider } from 'react-redux'; import { Router } from 'react-router'; import { bindActionCreators } from 'redux'; @@ -120,6 +120,7 @@ export default class AppRenderer { private lastDisconnectedLocation?: Partial<ILocation>; private relayListPair!: IRelayListPair; private tunnelState!: TunnelState; + private optimisticTunnelState?: TunnelState['state']; private settings!: ISettings; private guiSettings!: IGuiSettingsState; private doingLogin = false; @@ -323,39 +324,48 @@ export default class AppRenderer { } public async connectTunnel(): Promise<void> { - const state = this.tunnelState.state; + const state = this.optimisticTunnelState ?? this.tunnelState.state; // connect only if tunnel is disconnected or blocked. if (state === 'disconnecting' || state === 'disconnected' || state === 'error') { // switch to the connecting state ahead of time to make the app look more responsive - void this.updateLocation({ state: 'connecting' }); - this.reduxActions.connection.connecting(); + this.optimisticTunnelState = 'connecting'; + batch(() => { + void this.updateLocation({ state: 'connecting' }); + this.reduxActions.connection.connecting(); + }); return IpcRendererEventChannel.tunnel.connect(); } } public async disconnectTunnel(): Promise<void> { - const state = this.tunnelState.state; + const state = this.optimisticTunnelState ?? this.tunnelState.state; // disconnect only if tunnel is connected, connecting or blocked. if (state === 'connecting' || state === 'connected' || state === 'error') { // switch to the disconnecting state ahead of time to make the app look more responsive - void this.updateLocation({ state: 'disconnecting', details: 'nothing' }); - this.reduxActions.connection.disconnecting('nothing'); + this.optimisticTunnelState = 'disconnecting'; + batch(() => { + void this.updateLocation({ state: 'disconnecting', details: 'nothing' }); + this.reduxActions.connection.disconnecting('nothing'); + }); return IpcRendererEventChannel.tunnel.disconnect(); } } public async reconnectTunnel(): Promise<void> { - const state = this.tunnelState.state; + const state = this.optimisticTunnelState ?? this.tunnelState.state; // reconnect only if tunnel is connected or connecting. if (state === 'connecting' || state === 'connected') { // switch to the connecting state ahead of time to make the app look more responsive - void this.updateLocation({ state: 'connecting' }); - this.reduxActions.connection.connecting(); + this.optimisticTunnelState = 'connecting'; + batch(() => { + void this.updateLocation({ state: 'connecting' }); + this.reduxActions.connection.connecting(); + }); return IpcRendererEventChannel.tunnel.reconnect(); } |
