|
|
@@ -40,12 +40,24 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() { |
|
|
|
return tunnel |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Get first found tunnel in map with given name |
|
|
|
*/ |
|
|
|
fun getTunnelByName(tunnelName: String): ObservableTunnel? { |
|
|
|
return tunnelMap.find { it.name == tunnelName } |
|
|
|
} |
|
|
|
|
|
|
|
fun create(name: String, config: Config?): CompletionStage<ObservableTunnel> { |
|
|
|
if (Tunnel.isNameInvalid(name)) |
|
|
|
return CompletableFuture.failedFuture(IllegalArgumentException(context.getString(R.string.tunnel_error_invalid_name))) |
|
|
|
if (tunnelMap.containsKey(name)) |
|
|
|
if (tunnelMap.containsKey(name)) { |
|
|
|
return CompletableFuture.failedFuture(IllegalArgumentException(context.getString(R.string.tunnel_error_already_exists, name))) |
|
|
|
return getAsyncWorker().supplyAsync { configStore.create(name, config!!) }.thenApply { addToList(name, it, Tunnel.State.DOWN) } |
|
|
|
} |
|
|
|
return getAsyncWorker().supplyAsync { |
|
|
|
configStore.create(name, config!!) |
|
|
|
}.thenApply { |
|
|
|
addToList(name, it, Tunnel.State.DOWN) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fun delete(tunnel: ObservableTunnel): CompletionStage<Void> { |
|
|
@@ -94,7 +106,9 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() { |
|
|
|
|
|
|
|
fun onCreate() { |
|
|
|
getAsyncWorker().supplyAsync { configStore.enumerate() } |
|
|
|
.thenAcceptBoth(getAsyncWorker().supplyAsync { getBackend().runningTunnelNames }, this::onTunnelsLoaded) |
|
|
|
.thenAcceptBoth( |
|
|
|
getAsyncWorker().supplyAsync { getBackend().runningTunnelNames } |
|
|
|
) { present, running -> this.onTunnelsLoaded(present, running) } |
|
|
|
.whenComplete(ExceptionLoggers.E) |
|
|
|
} |
|
|
|
|
|
|
@@ -102,8 +116,10 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() { |
|
|
|
for (name in present) |
|
|
|
addToList(name, null, if (running.contains(name)) Tunnel.State.UP else Tunnel.State.DOWN) |
|
|
|
val lastUsedName = getSharedPreferences().getString(KEY_LAST_USED_TUNNEL, null) |
|
|
|
if (lastUsedName != null) |
|
|
|
|
|
|
|
if (lastUsedName != null) { |
|
|
|
lastUsedTunnel = tunnelMap[lastUsedName] |
|
|
|
} |
|
|
|
var toComplete: Array<CompletableFuture<Void>> |
|
|
|
synchronized(delayedLoadRestoreTunnels) { |
|
|
|
haveLoaded = true |
|
|
@@ -123,7 +139,17 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() { |
|
|
|
|
|
|
|
fun refreshTunnelStates() { |
|
|
|
getAsyncWorker().supplyAsync { getBackend().runningTunnelNames } |
|
|
|
.thenAccept { running: Set<String> -> for (tunnel in tunnelMap) tunnel.onStateChanged(if (running.contains(tunnel.name)) Tunnel.State.UP else Tunnel.State.DOWN) } |
|
|
|
.thenAccept { running: Set<String> -> |
|
|
|
for (tunnel in tunnelMap) { |
|
|
|
tunnel.onStateChanged( |
|
|
|
if (running.contains(tunnel.name)) { |
|
|
|
Tunnel.State.UP |
|
|
|
} else { |
|
|
|
Tunnel.State.DOWN |
|
|
|
} |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
.whenComplete(ExceptionLoggers.E) |
|
|
|
} |
|
|
|
|
|
|
@@ -139,12 +165,36 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() { |
|
|
|
} |
|
|
|
val previouslyRunning = getSharedPreferences().getStringSet(KEY_RUNNING_TUNNELS, null) |
|
|
|
?: return CompletableFuture.completedFuture(null) |
|
|
|
return CompletableFuture.allOf(*tunnelMap.filter { previouslyRunning.contains(it.name) }.map { setTunnelState(it, Tunnel.State.UP).toCompletableFuture() }.toTypedArray()) |
|
|
|
|
|
|
|
return CompletableFuture.allOf( |
|
|
|
*tunnelMap |
|
|
|
.filter { previouslyRunning.contains(it.name) } |
|
|
|
.map { setTunnelState(it, Tunnel.State.UP).toCompletableFuture() } |
|
|
|
.toTypedArray()) |
|
|
|
} |
|
|
|
|
|
|
|
@SuppressLint("ApplySharedPref") |
|
|
|
fun saveState() { |
|
|
|
getSharedPreferences().edit().putStringSet(KEY_RUNNING_TUNNELS, tunnelMap.filter { it.state == Tunnel.State.UP }.map { it.name }.toSet()).commit() |
|
|
|
getSharedPreferences().edit().putStringSet( |
|
|
|
KEY_RUNNING_TUNNELS, |
|
|
|
tunnelMap |
|
|
|
.filter { it.state == Tunnel.State.UP } |
|
|
|
.map { it.name } |
|
|
|
.toSet() |
|
|
|
).commit() |
|
|
|
getSharedPreferences().edit().putBoolean(KEY_RESTORE_ON_BOOT, upTunnelsExist()).commit() |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Check tunnel's map for tunnels with UP state. |
|
|
|
*/ |
|
|
|
private fun upTunnelsExist() : Boolean { |
|
|
|
tunnelMap.forEach { |
|
|
|
if (it.state == Tunnel.State.UP) { |
|
|
|
return true |
|
|
|
} |
|
|
|
} |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
fun setTunnelConfig(tunnel: ObservableTunnel, config: Config): CompletionStage<Config> = getAsyncWorker().supplyAsync { |
|
|
@@ -183,13 +233,15 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fun setTunnelState(tunnel: ObservableTunnel, state: Tunnel.State): CompletionStage<Tunnel.State> = tunnel.configAsync |
|
|
|
.thenCompose { getAsyncWorker().supplyAsync { getBackend().setState(tunnel, state, it) } } |
|
|
|
.whenComplete { newState, e -> |
|
|
|
fun setTunnelState(tunnel: ObservableTunnel, state: Tunnel.State): CompletionStage<Tunnel.State> = |
|
|
|
tunnel.configAsync.thenCompose { |
|
|
|
getAsyncWorker().supplyAsync { getBackend().setState(tunnel, state, it) } |
|
|
|
}.whenComplete { newState, e -> |
|
|
|
// Ensure onStateChanged is always called (failure or not), and with the correct state. |
|
|
|
tunnel.onStateChanged(if (e == null) newState else tunnel.state) |
|
|
|
if (e == null && newState == Tunnel.State.UP) |
|
|
|
if (e == null && newState == Tunnel.State.UP) { |
|
|
|
lastUsedTunnel = tunnel |
|
|
|
} |
|
|
|
saveState() |
|
|
|
} |
|
|
|
|
|
|
@@ -218,7 +270,7 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fun getTunnelState(tunnel: ObservableTunnel): CompletionStage<Tunnel.State> = getAsyncWorker() |
|
|
|
private fun getTunnelState(tunnel: ObservableTunnel): CompletionStage<Tunnel.State> = getAsyncWorker() |
|
|
|
.supplyAsync { getBackend().getState(tunnel) }.thenApply(tunnel::onStateChanged) |
|
|
|
|
|
|
|
fun getTunnelStatistics(tunnel: ObservableTunnel): CompletionStage<Statistics> = getAsyncWorker() |
|
|
|