summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSamuel Holland <samuel@sholland.org>2018-01-09 10:03:06 -0600
committerSamuel Holland <samuel@sholland.org>2018-01-09 10:03:29 -0600
commit933a68558525ae634c8f78113f9ce02adf7146de (patch)
tree2e63762944476269ddf21bdffc71f27d40cd87b3
parentdaacc06a0dcf4e8de371b9e177627ecd82e0ba17 (diff)
model: Chain completions to avoid race conditions
Otherwise getConfigAsync().thenCompose(x -> setState()) would be unsafe. This reverts commit a6595a273afd50524cc66765c6bfbdcc34cb12e4. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--app/src/main/java/com/wireguard/android/model/Tunnel.java9
-rw-r--r--app/src/main/java/com/wireguard/android/model/TunnelManager.java32
2 files changed, 18 insertions, 23 deletions
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 67c5144e..7977d16a 100644
--- a/app/src/main/java/com/wireguard/android/model/Tunnel.java
+++ b/app/src/main/java/com/wireguard/android/model/Tunnel.java
@@ -91,21 +91,24 @@ public class Tunnel extends BaseObservable implements Keyed<String> {
return CompletableFuture.completedFuture(statistics);
}
- void onConfigChanged(final Config config) {
+ Config onConfigChanged(final Config config) {
this.config = config;
notifyPropertyChanged(BR.config);
+ return config;
}
- void onStateChanged(final State state) {
+ State onStateChanged(final State state) {
if (state != State.UP)
onStatisticsChanged(null);
this.state = state;
notifyPropertyChanged(BR.state);
+ return state;
}
- void onStatisticsChanged(final Statistics statistics) {
+ Statistics onStatisticsChanged(final Statistics statistics) {
this.statistics = statistics;
notifyPropertyChanged(BR.statistics);
+ return statistics;
}
public CompletionStage<Tunnel> rename(@NonNull final String name) {
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 1916ab74..4c053e9a 100644
--- a/app/src/main/java/com/wireguard/android/model/TunnelManager.java
+++ b/app/src/main/java/com/wireguard/android/model/TunnelManager.java
@@ -110,24 +110,18 @@ public final class TunnelManager extends BaseObservable {
}
CompletionStage<Config> getTunnelConfig(final Tunnel tunnel) {
- final CompletionStage<Config> completion =
- asyncWorker.supplyAsync(() -> configStore.load(tunnel.getName()));
- completion.thenAccept(tunnel::onConfigChanged);
- return completion;
+ return asyncWorker.supplyAsync(() -> configStore.load(tunnel.getName()))
+ .thenApply(tunnel::onConfigChanged);
}
CompletionStage<State> getTunnelState(final Tunnel tunnel) {
- final CompletionStage<State> completion =
- asyncWorker.supplyAsync(() -> backend.getState(tunnel));
- completion.thenAccept(tunnel::onStateChanged);
- return completion;
+ return asyncWorker.supplyAsync(() -> backend.getState(tunnel))
+ .thenApply(tunnel::onStateChanged);
}
CompletionStage<Statistics> getTunnelStatistics(final Tunnel tunnel) {
- final CompletionStage<Statistics> completion =
- asyncWorker.supplyAsync(() -> backend.getStatistics(tunnel));
- completion.thenAccept(tunnel::onStatisticsChanged);
- return completion;
+ return asyncWorker.supplyAsync(() -> backend.getStatistics(tunnel))
+ .thenApply(tunnel::onStatisticsChanged);
}
public ObservableKeyedList<String, Tunnel> getTunnels() {
@@ -227,23 +221,21 @@ public final class TunnelManager extends BaseObservable {
}
CompletionStage<Config> setTunnelConfig(final Tunnel tunnel, final Config config) {
- final CompletionStage<Config> completion = asyncWorker.supplyAsync(() -> {
+ return asyncWorker.supplyAsync(() -> {
final Config appliedConfig = backend.applyConfig(tunnel, config);
return configStore.save(tunnel.getName(), appliedConfig);
- });
- completion.thenAccept(tunnel::onConfigChanged);
- return completion;
+ }).thenApply(tunnel::onConfigChanged);
}
CompletionStage<State> setTunnelState(final Tunnel tunnel, final State state) {
- final CompletionStage<State> completion =
- asyncWorker.supplyAsync(() -> backend.setState(tunnel, state));
- completion.whenComplete((newState, e) -> {
+ // Ensure the configuration is loaded before trying to use it.
+ return tunnel.getConfigAsync().thenCompose(x ->
+ asyncWorker.supplyAsync(() -> backend.setState(tunnel, state))
+ ).whenComplete((newState, e) -> {
// Ensure onStateChanged is always called (failure or not), and with the correct state.
tunnel.onStateChanged(e == null ? newState : tunnel.getState());
if (e == null && newState == State.UP)
setLastUsedTunnel(tunnel);
});
- return completion;
}
}