summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-09-02 13:02:18 +0200
committerOskar Nyberg <oskar@mullvad.net>2021-09-06 14:38:27 +0200
commit823c4c576344eefbcb20abd6c7362f183f615764 (patch)
tree793ff0168ebcde1220977fb2fa57094f3a0a49fe
parent8de764350aaf998b7305b8167ee1c4121069a576 (diff)
downloadmullvadvpn-823c4c576344eefbcb20abd6c7362f183f615764.tar.xz
mullvadvpn-823c4c576344eefbcb20abd6c7362f183f615764.zip
Improve handling of next state
-rw-r--r--gui/src/main/index.ts43
-rw-r--r--gui/src/renderer/app.tsx30
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();
}