aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt')
-rw-r--r--ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt146
1 files changed, 146 insertions, 0 deletions
diff --git a/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt b/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt
new file mode 100644
index 00000000..227c1291
--- /dev/null
+++ b/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt
@@ -0,0 +1,146 @@
+/*
+ * Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package com.wireguard.android.model
+
+import android.util.Log
+import androidx.databinding.BaseObservable
+import androidx.databinding.Bindable
+import com.wireguard.android.BR
+import com.wireguard.android.backend.Statistics
+import com.wireguard.android.backend.Tunnel
+import com.wireguard.android.databinding.Keyed
+import com.wireguard.android.util.applicationScope
+import com.wireguard.config.Config
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * Encapsulates the volatile and nonvolatile state of a WireGuard tunnel.
+ */
+class ObservableTunnel internal constructor(
+ private val manager: TunnelManager,
+ private var name: String,
+ config: Config?,
+ state: Tunnel.State
+) : BaseObservable(), Keyed<String>, Tunnel {
+ override val key
+ get() = name
+
+ @Bindable
+ override fun getName() = name
+
+ suspend fun setNameAsync(name: String): String = withContext(Dispatchers.Main.immediate) {
+ if (name != this@ObservableTunnel.name)
+ manager.setTunnelName(this@ObservableTunnel, name)
+ else
+ this@ObservableTunnel.name
+ }
+
+ fun onNameChanged(name: String): String {
+ this.name = name
+ notifyPropertyChanged(BR.name)
+ return name
+ }
+
+
+ @get:Bindable
+ var state = state
+ private set
+
+ override fun onStateChange(newState: Tunnel.State) {
+ onStateChanged(newState)
+ }
+
+ fun onStateChanged(state: Tunnel.State): Tunnel.State {
+ if (state != Tunnel.State.UP) onStatisticsChanged(null)
+ this.state = state
+ notifyPropertyChanged(BR.state)
+ return state
+ }
+
+ suspend fun setStateAsync(state: Tunnel.State): Tunnel.State = withContext(Dispatchers.Main.immediate) {
+ if (state != this@ObservableTunnel.state)
+ manager.setTunnelState(this@ObservableTunnel, state)
+ else
+ this@ObservableTunnel.state
+ }
+
+
+ @get:Bindable
+ var config = config
+ get() {
+ if (field == null)
+ // Opportunistically fetch this if we don't have a cached one, and rely on data bindings to update it eventually
+ applicationScope.launch {
+ try {
+ manager.getTunnelConfig(this@ObservableTunnel)
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
+ return field
+ }
+ private set
+
+ suspend fun getConfigAsync(): Config = withContext(Dispatchers.Main.immediate) {
+ config ?: manager.getTunnelConfig(this@ObservableTunnel)
+ }
+
+ suspend fun setConfigAsync(config: Config): Config = withContext(Dispatchers.Main.immediate) {
+ this@ObservableTunnel.config.let {
+ if (config != it)
+ manager.setTunnelConfig(this@ObservableTunnel, config)
+ else
+ it
+ }
+ }
+
+ fun onConfigChanged(config: Config?): Config? {
+ this.config = config
+ notifyPropertyChanged(BR.config)
+ return config
+ }
+
+
+ @get:Bindable
+ var statistics: Statistics? = null
+ get() {
+ if (field == null || field?.isStale != false)
+ // Opportunistically fetch this if we don't have a cached one, and rely on data bindings to update it eventually
+ applicationScope.launch {
+ try {
+ manager.getTunnelStatistics(this@ObservableTunnel)
+ } catch (e: Throwable) {
+ Log.e(TAG, Log.getStackTraceString(e))
+ }
+ }
+ return field
+ }
+ private set
+
+ suspend fun getStatisticsAsync(): Statistics = withContext(Dispatchers.Main.immediate) {
+ statistics.let {
+ if (it == null || it.isStale)
+ manager.getTunnelStatistics(this@ObservableTunnel)
+ else
+ it
+ }
+ }
+
+ fun onStatisticsChanged(statistics: Statistics?): Statistics? {
+ this.statistics = statistics
+ notifyPropertyChanged(BR.statistics)
+ return statistics
+ }
+
+
+ suspend fun deleteAsync() = manager.delete(this)
+
+
+ companion object {
+ private const val TAG = "WireGuard/ObservableTunnel"
+ }
+}