diff options
author | Samuel Holland <samuel@sholland.org> | 2018-01-01 02:06:37 -0600 |
---|---|---|
committer | Samuel Holland <samuel@sholland.org> | 2018-01-06 04:09:29 -0600 |
commit | 609194fae2332e6f2ccd7a4464bfa492ad661a6f (patch) | |
tree | 96a7cd9846a093dfcdacfef285b0a4d77000edf0 /app/src/main/java/com/wireguard/android/configStore | |
parent | 4c0869393e2d8f52b9bcf312286dca8ced2e1900 (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.java | 65 | ||||
-rw-r--r-- | app/src/main/java/com/wireguard/android/configStore/FileConfigStore.java | 98 |
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; + } + }); + } +} |