diff --git a/.gitignore b/.gitignore index 3ec96e5..b8742ef 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ build/ /captures .externalNativeBuild +.kotlin/ .idea/* !.idea/runConfigurations/ !.idea/copyright/ diff --git a/app/src/main/java/org/openziti/mobile/TunnelModel.kt b/app/src/main/java/org/openziti/mobile/TunnelModel.kt index 20cfb84..f85985f 100644 --- a/app/src/main/java/org/openziti/mobile/TunnelModel.kt +++ b/app/src/main/java/org/openziti/mobile/TunnelModel.kt @@ -8,6 +8,7 @@ import android.content.Context import android.util.Log import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore @@ -66,8 +67,8 @@ class TunnelModel( fun setDNS(server: String?, range: String?) = runBlocking { context().prefs.edit { settings -> - settings[NAMESERVER] = server ?: defaultDNS - settings[RANGE] = range ?: defaultRange + settings[NAMESERVER] = server ?: DEFAULT_DNS + settings[RANGE] = range ?: DEFAULT_RANGE } } @@ -85,7 +86,11 @@ class TunnelModel( } } - class TunnelIdentity(val id: String, val tunnelModel: TunnelModel): ViewModel() { + class TunnelIdentity( + val id: String, + private val tunnel: TunnelModel, + enable: Boolean = true + ): ViewModel() { val zitiID: String = with(URI(id)){ @@ -97,12 +102,12 @@ class TunnelModel( internal val name = MutableLiveData(id) fun status(): LiveData = status - internal val status = MutableLiveData("Loading") + internal val status = MutableLiveData("Loading") - internal val controller = MutableLiveData(" = enabled private val serviceMap = mutableMapOf() @@ -110,24 +115,31 @@ class TunnelModel( fun services(): LiveData> = services fun refresh() { - tunnelModel.refreshIdentity(id).handleAsync { _, ex -> - Log.w(TAG, "failed refresh", ex) + tunnel.refreshIdentity(id).handleAsync { _, ex -> + ex?.let { + Log.w(TAG, "failed refresh", it) + } } } fun setEnabled(on: Boolean) { - tunnelModel.enableIdentity(id, on).thenAccept { + if (on) + Log.i(TAG, "enabling[${name.value}]") + else + Log.i(TAG, "disabling[${name.value}]") + + tunnel.enableIdentity(id, on).thenAccept { enabled.postValue(on) if (on) - status.postValue("Disabled") - else status.postValue("Enabled") + else + status.postValue("Disabled") } } fun delete() { setEnabled(false) - tunnelModel.deleteIdentity(id) + tunnel.deleteIdentity(id) } internal fun processServiceUpdate(ev: ServiceEvent) { @@ -187,16 +199,23 @@ class TunnelModel( } } - private fun loadConfig(ident: String, cfg: ZitiConfig) { - Log.i("model", "loading identity[$ident]") - val cmd = LoadIdentity(ident, cfg) + private fun disabledKey(id: String) = booleanPreferencesKey("$id.disabled") + + private fun loadConfig(id: String, cfg: ZitiConfig) { + val disabled = runBlocking { + context().prefs.data.map { + it[disabledKey(id)] ?: false + }.first() + } + Log.i("model", "loading identity[$id] disabled[$disabled]") + val cmd = LoadIdentity(id, cfg, disabled) tunnel.processCmd(cmd).handleAsync { json: JsonElement? , ex: Throwable? -> if (ex != null) { Log.w("model", "failed to execute", ex) } else { - identities[ident] = TunnelIdentity(ident, this) + identities[id] = TunnelIdentity(id, this, !disabled) identitiesData.postValue(identities.values.toList()) - Log.i("model", "load result[$ident]: $json") + Log.i("model", "load result[$id]: $json") } } } @@ -262,8 +281,15 @@ class TunnelModel( private fun refreshIdentity(id: String) = tunnel.processCmd(RefreshIdentity(id)).thenAccept{} - private fun enableIdentity(id: String, on: Boolean) = - tunnel.processCmd(OnOffCommand(id, on)).thenAccept {} + private fun enableIdentity(id: String, on: Boolean): CompletableFuture { + val disabledKey = disabledKey(id) + runBlocking { + context().prefs.edit { + it[disabledKey] = !on + } + } + return tunnel.processCmd(OnOffCommand(id, on)).thenApply {} + } private fun deleteIdentity(identifier: String) { identities.remove(identifier) @@ -288,8 +314,8 @@ class TunnelModel( } companion object { - val TAG = TunnelModel::class.simpleName - val defaultDNS = "100.64.0.2" - val defaultRange = "100.64.0.0/10" + const val TAG = "tunnel-model" + const val DEFAULT_DNS = "100.64.0.2" + const val DEFAULT_RANGE = "100.64.0.0/10" } } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 4e69971..3d3e9b2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,8 +2,6 @@ * Copyright (c) 2021 NetFoundry. All rights reserved. */ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - plugins { alias(libs.plugins.android.app) apply(false) alias(libs.plugins.android.lib) apply(false) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bbb0412..0c31498 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,7 @@ android = "8.7.1" kotlin = "2.0.21" # ziti projects -ziti-tunnel-sdk = "1.2.0" +ziti-tunnel-sdk = "1.2.5" # 3rd part deps kotlinx-serialization-json = "1.7.3" diff --git a/tunnel/src/main/java/org/openziti/tunnel/TunnelCommand.kt b/tunnel/src/main/java/org/openziti/tunnel/TunnelCommand.kt index 4357e84..b54907c 100644 --- a/tunnel/src/main/java/org/openziti/tunnel/TunnelCommand.kt +++ b/tunnel/src/main/java/org/openziti/tunnel/TunnelCommand.kt @@ -57,7 +57,7 @@ enum class CMD { @Serializable data class OnOffCommand( @SerialName("Identifier") val identifier: String, - val on: Boolean + @SerialName("OnOff") val on: Boolean ) : TunnelCommand(CMD.IdentityOnOff) @Serializable data class RefreshIdentity( @@ -67,6 +67,7 @@ enum class CMD { @Serializable data class LoadIdentity( @SerialName("Identifier") val identifier: String, @SerialName("Config") val config: ZitiConfig, + @SerialName("Disabled") val disabled: Boolean, ): TunnelCommand(CMD.LoadIdentity) @Serializable data class Dump(