diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java index ed14a82f..e712c4a0 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java @@ -198,7 +198,7 @@ public class TunnelListFragment extends BaseFragment { case R.id.menu_action_delete: final CompletableFuture[] futures = getCheckedPositions() .mapToObj(pos -> (Tunnel) tunnelList.getItemAtPosition(pos)) - .map(tunnelManager::delete) + .map(Tunnel::delete) .toArray(CompletableFuture[]::new); CompletableFuture.allOf(futures) .thenApply(x -> futures.length) diff --git a/app/src/main/java/com/wireguard/android/model/Tunnel.java b/app/src/main/java/com/wireguard/android/model/Tunnel.java index e1a80456..7a0972c3 100644 --- a/app/src/main/java/com/wireguard/android/model/Tunnel.java +++ b/app/src/main/java/com/wireguard/android/model/Tunnel.java @@ -6,13 +6,10 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.wireguard.android.BR; -import com.wireguard.android.backend.Backend; -import com.wireguard.android.configStore.ConfigStore; import com.wireguard.android.util.ExceptionLoggers; import com.wireguard.android.util.Keyed; import com.wireguard.config.Config; -import java.util.Objects; import java.util.regex.Pattern; import java9.util.concurrent.CompletableFuture; @@ -25,19 +22,16 @@ import java9.util.concurrent.CompletionStage; public class Tunnel extends BaseObservable implements Keyed { public static final int NAME_MAX_LENGTH = 16; private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z0-9_=+.-]{1,16}"); - private static final String TAG = Tunnel.class.getSimpleName(); - private final Backend backend; - private final ConfigStore configStore; + private final TunnelManager manager; private final String name; private Config config; private State state; private Statistics statistics; - Tunnel(@NonNull final Backend backend, @NonNull final ConfigStore configStore, - @NonNull final String name, @Nullable final Config config, @NonNull final State state) { - this.backend = backend; - this.configStore = configStore; + Tunnel(@NonNull final TunnelManager manager, @NonNull final String name, + @Nullable final Config config, @NonNull final State state) { + this.manager = manager; this.name = name; this.config = config; this.state = state; @@ -47,16 +41,20 @@ public class Tunnel extends BaseObservable implements Keyed { return name != null && NAME_PATTERN.matcher(name).matches(); } + public CompletionStage delete() { + return manager.delete(this); + } + @Bindable public Config getConfig() { if (config == null) - getConfigAsync().whenComplete(ExceptionLoggers.D); + manager.getTunnelConfig(this).whenComplete(ExceptionLoggers.E); return config; } public CompletionStage getConfigAsync() { if (config == null) - return configStore.load(name).thenApply(this::setConfigInternal); + return manager.getTunnelConfig(this); return CompletableFuture.completedFuture(config); } @@ -65,7 +63,6 @@ public class Tunnel extends BaseObservable implements Keyed { return name; } - @Bindable public String getName() { return name; } @@ -73,13 +70,13 @@ public class Tunnel extends BaseObservable implements Keyed { @Bindable public State getState() { if (state == State.UNKNOWN) - getStateAsync().whenComplete(ExceptionLoggers.D); + manager.getTunnelState(this).whenComplete(ExceptionLoggers.E); return state; } public CompletionStage getStateAsync() { if (state == State.UNKNOWN) - return backend.getState(this).thenApply(this::setStateInternal); + return manager.getTunnelState(this); return CompletableFuture.completedFuture(state); } @@ -87,63 +84,49 @@ public class Tunnel extends BaseObservable implements Keyed { public Statistics getStatistics() { // FIXME: Check age of statistics. if (statistics == null) - getStatisticsAsync().whenComplete(ExceptionLoggers.D); + manager.getTunnelStatistics(this).whenComplete(ExceptionLoggers.E); return statistics; } public CompletionStage getStatisticsAsync() { // FIXME: Check age of statistics. if (statistics == null) - return backend.getStatistics(this).thenApply(this::setStatisticsInternal); + return manager.getTunnelStatistics(this); return CompletableFuture.completedFuture(statistics); } - private void onStateChanged(final State oldState, final State newState) { - if (newState != State.UP) - setStatisticsInternal(null); - } - - public CompletionStage setConfig(@NonNull final Config config) { - if (!config.equals(this.config)) { - return backend.applyConfig(this, config) - .thenCompose(cfg -> configStore.save(name, cfg)) - .thenApply(this::setConfigInternal); - } - return CompletableFuture.completedFuture(this.config); - } - - private Config setConfigInternal(final Config config) { - if (Objects.equals(this.config, config)) - return config; + Config onConfigChanged(final Config config) { this.config = config; notifyPropertyChanged(BR.config); return config; } - public CompletionStage setState(@NonNull final State state) { - if (state != this.state) - return backend.setState(this, state) - .thenApply(this::setStateInternal); - return CompletableFuture.completedFuture(this.state); - } - - private State setStateInternal(final State state) { - if (Objects.equals(this.state, state)) - return state; - onStateChanged(this.state, state); + State onStateChanged(final State state) { + if (state != State.UP) + onStatisticsChanged(null); this.state = state; notifyPropertyChanged(BR.state); return state; } - private Statistics setStatisticsInternal(final Statistics statistics) { - if (Objects.equals(this.statistics, statistics)) - return statistics; + Statistics onStatisticsChanged(final Statistics statistics) { this.statistics = statistics; notifyPropertyChanged(BR.statistics); return statistics; } + public CompletionStage setConfig(@NonNull final Config config) { + if (!config.equals(this.config)) + return manager.setTunnelConfig(this, config); + return CompletableFuture.completedFuture(this.config); + } + + public CompletionStage setState(@NonNull final State state) { + if (state != this.state) + return manager.setTunnelState(this, state); + return CompletableFuture.completedFuture(this.state); + } + public enum State { DOWN, TOGGLE, diff --git a/app/src/main/java/com/wireguard/android/model/TunnelManager.java b/app/src/main/java/com/wireguard/android/model/TunnelManager.java index 3682cfcd..123f5b51 100644 --- a/app/src/main/java/com/wireguard/android/model/TunnelManager.java +++ b/app/src/main/java/com/wireguard/android/model/TunnelManager.java @@ -1,12 +1,12 @@ package com.wireguard.android.model; import android.content.SharedPreferences; -import android.util.Log; import com.wireguard.android.Application.ApplicationScope; import com.wireguard.android.backend.Backend; import com.wireguard.android.configStore.ConfigStore; import com.wireguard.android.model.Tunnel.State; +import com.wireguard.android.model.Tunnel.Statistics; import com.wireguard.android.util.ExceptionLoggers; import com.wireguard.android.util.KeyedObservableList; import com.wireguard.android.util.SortedKeyedObservableArrayList; @@ -49,36 +49,37 @@ public final class TunnelManager { } private Tunnel add(final String name, final Config config, final State state) { - final Tunnel tunnel = new Tunnel(backend, configStore, name, config, state); + final Tunnel tunnel = new Tunnel(this, name, config, state); tunnels.add(tunnel); return tunnel; } - private Tunnel add(final String name) { - return add(name, null, State.UNKNOWN); - } - public CompletionStage create(final String name, final Config config) { - Log.v(TAG, "Requested create tunnel " + name + " with config\n" + config); if (!Tunnel.isNameValid(name)) return CompletableFuture.failedFuture(new IllegalArgumentException("Invalid name")); if (tunnels.containsKey(name)) { final String message = "Tunnel " + name + " already exists"; return CompletableFuture.failedFuture(new IllegalArgumentException(message)); } - return configStore.create(name, config) - .thenApply(savedConfig -> add(name, savedConfig, State.DOWN)); + return configStore.create(name, config).thenApply(cfg -> add(name, cfg, State.DOWN)); } - public CompletionStage delete(final Tunnel tunnel) { - Log.v(TAG, "Requested delete tunnel " + tunnel.getName() + " state=" + tunnel.getState()); - return backend.setState(tunnel, State.DOWN) + CompletionStage delete(final Tunnel tunnel) { + return setTunnelState(tunnel, State.DOWN) .thenCompose(x -> configStore.delete(tunnel.getName())) - .thenAccept(x -> { - tunnels.remove(tunnel); - if (tunnel.getName().equals(preferences.getString(KEY_PRIMARY_TUNNEL, null))) - preferences.edit().remove(KEY_PRIMARY_TUNNEL).apply(); - }); + .thenAccept(x -> remove(tunnel)); + } + + CompletionStage getTunnelConfig(final Tunnel tunnel) { + return configStore.load(tunnel.getName()).thenApply(tunnel::onConfigChanged); + } + + CompletionStage getTunnelState(final Tunnel tunnel) { + return backend.getState(tunnel).thenApply(tunnel::onStateChanged); + } + + CompletionStage getTunnelStatistics(final Tunnel tunnel) { + return backend.getStatistics(tunnel).thenApply(tunnel::onStatisticsChanged); } public KeyedObservableList getTunnels() { @@ -86,12 +87,16 @@ public final class TunnelManager { } public void onCreate() { - Log.v(TAG, "onCreate triggered"); configStore.enumerate().thenAcceptBoth(backend.enumerate(), (names, running) -> { - for (final String name : names) { + for (final String name : names) add(name, null, running.contains(name) ? State.UP : State.DOWN); - } - }).whenComplete(ExceptionLoggers.D); + }).whenComplete(ExceptionLoggers.E); + } + + private void remove(final Tunnel tunnel) { + if (tunnel.getName().equals(preferences.getString(KEY_PRIMARY_TUNNEL, null))) + preferences.edit().remove(KEY_PRIMARY_TUNNEL).apply(); + tunnels.remove(tunnel); } public CompletionStage restoreState() { @@ -114,4 +119,15 @@ public final class TunnelManager { preferences.edit().putStringSet(KEY_RUNNING_TUNNELS, runningTunnels).apply(); return CompletableFuture.completedFuture(null); } + + CompletionStage setTunnelConfig(final Tunnel tunnel, final Config config) { + return backend.applyConfig(tunnel, config) + .thenCompose(cfg -> configStore.save(tunnel.getName(), cfg)) + .thenApply(tunnel::onConfigChanged); + } + + CompletionStage setTunnelState(final Tunnel tunnel, final State state) { + return backend.setState(tunnel, state) + .thenApply(tunnel::onStateChanged); + } }