wireguard-android/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt
Jason A. Donenfeld bf84e26a86 global: bump copyright year
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-10-29 16:47:12 +02:00

147 lines
4.3 KiB
Kotlin

/*
* Copyright © 2017-2021 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"
}
}