summaryrefslogtreecommitdiffhomepage
path: root/app/src/main/java/com/wireguard/android/configStore
diff options
context:
space:
mode:
authorSamuel Holland <samuel@sholland.org>2018-01-01 02:06:37 -0600
committerSamuel Holland <samuel@sholland.org>2018-01-06 04:09:29 -0600
commit609194fae2332e6f2ccd7a4464bfa492ad661a6f (patch)
tree96a7cd9846a093dfcdacfef285b0a4d77000edf0 /app/src/main/java/com/wireguard/android/configStore
parent4c0869393e2d8f52b9bcf312286dca8ced2e1900 (diff)
Serviceless rewrite, part 1
Signed-off-by: Samuel Holland <samuel@sholland.org>
Diffstat (limited to 'app/src/main/java/com/wireguard/android/configStore')
-rw-r--r--app/src/main/java/com/wireguard/android/configStore/ConfigStore.java65
-rw-r--r--app/src/main/java/com/wireguard/android/configStore/FileConfigStore.java98
2 files changed, 163 insertions, 0 deletions
diff --git a/app/src/main/java/com/wireguard/android/configStore/ConfigStore.java b/app/src/main/java/com/wireguard/android/configStore/ConfigStore.java
new file mode 100644
index 00000000..19bb6bf5
--- /dev/null
+++ b/app/src/main/java/com/wireguard/android/configStore/ConfigStore.java
@@ -0,0 +1,65 @@
+package com.wireguard.android.configStore;
+
+import com.wireguard.config.Config;
+
+import java.util.Set;
+
+import java9.util.concurrent.CompletionStage;
+
+/**
+ * Interface for persistent storage providers for WireGuard configurations.
+ */
+
+public interface ConfigStore {
+ /**
+ * Create a persistent tunnel, which must have a unique name within the persistent storage
+ * medium.
+ *
+ * @param name The name of the tunnel to create.
+ * @param config Configuration for the new tunnel.
+ * @return A future completed when the tunnel and its configuration have been saved to
+ * persistent storage. This future encapsulates the configuration that was actually saved to
+ * persistent storage. This future will always be completed on the main thread.
+ */
+ CompletionStage<Config> create(final String name, final Config config);
+
+ /**
+ * Delete a persistent tunnel.
+ *
+ * @param name The name of the tunnel to delete.
+ * @return A future completed when the tunnel and its configuration have been deleted. This
+ * future will always be completed on the main thread.
+ */
+ CompletionStage<Void> delete(final String name);
+
+ /**
+ * Enumerate the names of tunnels present in persistent storage.
+ *
+ * @return A future completed when the set of present tunnel names is available. This future
+ * will always be completed on the main thread.
+ */
+ CompletionStage<Set<String>> enumerate();
+
+ /**
+ * Load the configuration for the tunnel given by {@code name}.
+ *
+ * @param name The identifier for the configuration in persistent storage (i.e. the name of the
+ * tunnel).
+ * @return A future completed when an in-memory representation of the configuration is
+ * available. This future encapsulates the configuration loaded from persistent storage. This
+ * future will always be completed on the main thread.
+ */
+ CompletionStage<Config> load(final String name);
+
+ /**
+ * Save the configuration for an existing tunnel given by {@code name}.
+ *
+ * @param name The identifier for the configuration in persistent storage (i.e. the name of
+ * the tunnel).
+ * @param config An updated configuration object for the tunnel.
+ * @return A future completed when the configuration has been saved to persistent storage. This
+ * future encapsulates the configuration that was actually saved to persistent storage. This
+ * future will always be completed on the main thread.
+ */
+ CompletionStage<Config> save(final String name, final Config config);
+}
diff --git a/app/src/main/java/com/wireguard/android/configStore/FileConfigStore.java b/app/src/main/java/com/wireguard/android/configStore/FileConfigStore.java
new file mode 100644
index 00000000..099bc0d3
--- /dev/null
+++ b/app/src/main/java/com/wireguard/android/configStore/FileConfigStore.java
@@ -0,0 +1,98 @@
+package com.wireguard.android.configStore;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.wireguard.android.Application.ApplicationContext;
+import com.wireguard.android.util.AsyncWorker;
+import com.wireguard.config.Config;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Set;
+
+import java9.util.concurrent.CompletionStage;
+import java9.util.stream.Collectors;
+import java9.util.stream.Stream;
+
+/**
+ * Created by samuel on 12/28/17.
+ */
+
+public final class FileConfigStore implements ConfigStore {
+ private static final String TAG = FileConfigStore.class.getSimpleName();
+
+ private final AsyncWorker asyncWorker;
+ private final Context context;
+
+ public FileConfigStore(final AsyncWorker asyncWorker,
+ @ApplicationContext final Context context) {
+ this.asyncWorker = asyncWorker;
+ this.context = context;
+ }
+
+ @Override
+ public CompletionStage<Config> create(final String name, final Config config) {
+ return asyncWorker.supplyAsync(() -> {
+ final File file = fileFor(name);
+ if (!file.createNewFile()) {
+ final String message = "Configuration file " + file.getName() + " already exists";
+ throw new IllegalStateException(message);
+ }
+ try (FileOutputStream stream = new FileOutputStream(file, false)) {
+ stream.write(config.toString().getBytes(StandardCharsets.UTF_8));
+ return config;
+ }
+ });
+ }
+
+ @Override
+ public CompletionStage<Void> delete(final String name) {
+ return asyncWorker.runAsync(() -> {
+ final File file = fileFor(name);
+ if (!file.delete())
+ throw new IOException("Cannot delete configuration file " + file.getName());
+ });
+ }
+
+ @Override
+ public CompletionStage<Set<String>> enumerate() {
+ return asyncWorker.supplyAsync(() -> Stream.of(context.fileList())
+ .filter(name -> name.endsWith(".conf"))
+ .map(name -> name.substring(0, name.length() - ".conf".length()))
+ .collect(Collectors.toUnmodifiableSet()));
+ }
+
+ private File fileFor(final String name) {
+ return new File(context.getFilesDir(), name + ".conf");
+ }
+
+ @Override
+ public CompletionStage<Config> load(final String name) {
+ return asyncWorker.supplyAsync(() -> {
+ try (FileInputStream stream = new FileInputStream(fileFor(name))) {
+ return Config.from(stream);
+ }
+ });
+ }
+
+ @Override
+ public CompletionStage<Config> save(final String name, final Config config) {
+ Log.d(TAG, "Requested save config for tunnel " + name);
+ return asyncWorker.supplyAsync(() -> {
+ final File file = fileFor(name);
+ if (!file.isFile()) {
+ final String message = "Configuration file " + file.getName() + " not found";
+ throw new IllegalStateException(message);
+ }
+ try (FileOutputStream stream = new FileOutputStream(file, false)) {
+ Log.d(TAG, "Writing out config for tunnel " + name);
+ stream.write(config.toString().getBytes(StandardCharsets.UTF_8));
+ return config;
+ }
+ });
+ }
+}