Skip to content

Commit

Permalink
fix: start failure bugs
Browse files Browse the repository at this point in the history
integration account links

fix: environment switching with account controller restarts
  • Loading branch information
zaneschepke committed Nov 13, 2024
1 parent e7aab26 commit 03b4353
Show file tree
Hide file tree
Showing 17 changed files with 83 additions and 254 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ class NymTunnelManager @Inject constructor(
override val stateFlow: Flow<TunnelManagerState> = _state.onStart {
val isMnemonicStored = isMnemonicStored()
_state.update {
it.copy(isMnemonicStored = isMnemonicStored,
accountLinks = if(isMnemonicStored) getAccountLinks() else null)
it.copy(
isMnemonicStored = isMnemonicStored,
accountLinks = if (isMnemonicStored) getAccountLinks() else null,
)
}
}.stateIn(applicationScope.plus(ioDispatcher), SharingStarted.WhileSubscribed(Constants.SUBSCRIPTION_TIMEOUT), TunnelManagerState())

Expand Down Expand Up @@ -197,6 +199,10 @@ class NymTunnelManager @Inject constructor(
}
}
BackendMessage.None -> Unit
is BackendMessage.StartFailure -> notificationService.showNotification(
title = context.getString(R.string.connection_failed),
description = backendMessage.exception.toUserMessage(context),
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ data class TunnelManagerState(
val tunnelStatistics: Statistics = Statistics(),
val backendMessage: BackendMessage = BackendMessage.None,
val isMnemonicStored: Boolean = false,
val accountLinks: AccountLinks? = null
val accountLinks: AccountLinks? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package net.nymtech.nymvpn.ui.model

import net.nymtech.nymvpn.util.StringValue
import nym_vpn_lib.ErrorStateReason
import nym_vpn_lib.VpnException

sealed class StateMessage {
data class Status(val message: StringValue) : StateMessage()
data class Error(val reason: ErrorStateReason) : StateMessage()
data class StartError(val exception: VpnException) : StateMessage()
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ fun MainScreen(appViewModel: AppViewModel, appUiState: AppUiState, autoStart: Bo
message = it.reason.toUserMessage(context),
textColor = CustomColors.error,
)

is StateMessage.StartError -> {
StatusInfoLabel(
message = it.exception.toUserMessage(context),
textColor = CustomColors.error,
)
}
}
}
AnimatedVisibility(visible = uiState.connectionState is ConnectionState.Connected) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import kotlinx.coroutines.launch
import net.nymtech.nymvpn.data.SettingsRepository
import net.nymtech.nymvpn.service.tunnel.TunnelManager
import net.nymtech.nymvpn.ui.model.ConnectionState
import net.nymtech.nymvpn.ui.model.StateMessage
import net.nymtech.nymvpn.ui.model.StateMessage.*
import net.nymtech.nymvpn.util.Constants
import net.nymtech.nymvpn.util.extensions.convertSecondsToTimeString
import net.nymtech.vpn.backend.Tunnel
Expand All @@ -31,10 +31,13 @@ constructor(
var stateMessage = connectionState.stateMessage
when (manager.backendMessage) {
is BackendMessage.Failure -> {
stateMessage = StateMessage.Error(manager.backendMessage.reason)
stateMessage = Error(manager.backendMessage.reason)
}
BackendMessage.None -> stateMessage = connectionState.stateMessage
is BackendMessage.BandwidthAlert -> Unit
is BackendMessage.StartFailure -> {
stateMessage = StartError(manager.backendMessage.exception)
}
}
MainUiState(
connectionTime = connectionTime,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ fun SettingsScreen(appViewModel: AppViewModel, appUiState: AppUiState, viewModel
},
title = { Text(stringResource(R.string.account), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) },
onClick = {
appUiState.managerState.accountLinks?.account?.let{
appUiState.managerState.accountLinks?.account?.let {
Timber.d("Account url: $it")
context.openWebUrl(it)
} ?: snackbar.showMessage("Not available")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import net.nymtech.nymvpn.data.SettingsRepository
import net.nymtech.nymvpn.service.tunnel.TunnelManager
import javax.inject.Inject

@HiltViewModel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ fun CredentialScreen(appUiState: AppUiState, appViewModel: AppViewModel, viewMod
append(" ")
pushStringAnnotation(
tag = "create",
annotation = appUiState.settings.environment.createAccountUrl.toString(),
annotation = appUiState.managerState.accountLinks?.signUp ?: stringResource(R.string.create_account_url),
)
withStyle(style = SpanStyle(color = MaterialTheme.colorScheme.primary)) {
append(stringResource(id = R.string.create_account))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,30 @@ import kotlinx.coroutines.launch
import net.nymtech.nymvpn.R
import net.nymtech.nymvpn.data.SettingsRepository
import net.nymtech.nymvpn.service.country.CountryCacheService
import net.nymtech.nymvpn.service.gateway.NymApiService
import net.nymtech.nymvpn.service.tunnel.TunnelManager
import net.nymtech.nymvpn.ui.common.snackbar.SnackbarController
import net.nymtech.nymvpn.util.StringValue
import net.nymtech.vpn.backend.Backend
import net.nymtech.vpn.backend.Tunnel
import net.nymtech.vpn.util.extensions.export
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Provider

@HiltViewModel
class EnvironmentViewModel
@Inject
constructor(
private val settingsRepository: SettingsRepository,
private val tunnelManager: TunnelManager,
private val backend: Provider<Backend>,
private val cacheService: CountryCacheService,
private val nymApiService: NymApiService,
) : ViewModel() {

fun onEnvironmentChange(environment: Tunnel.Environment) = viewModelScope.launch {
if (tunnelManager.getState() == Tunnel.State.Down) {
settingsRepository.setEnvironment(environment)
runCatching {
Timber.d("Exporting new env config")
nymApiService.getEnvironment(environment).export()
backend.get().init(environment)
}.onFailure { Timber.e(it) }
launch {
cacheService.updateExitCountriesCache()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.navigation.NavGraph.Companion.findStartDestination
import net.nymtech.nymvpn.NymVpn
import net.nymtech.nymvpn.ui.Route
import nym_vpn_lib.ErrorStateReason
import nym_vpn_lib.VpnException
import kotlin.reflect.KClass

fun Dp.scaledHeight(): Dp {
Expand Down Expand Up @@ -69,3 +70,21 @@ fun ErrorStateReason.toUserMessage(context: Context): String {
ErrorStateReason.BAD_BANDWIDTH_INCREASE -> "Bad bandwidth increase."
}
}

fun VpnException.toUserMessage(context: Context): String {
return when (this) {
is VpnException.AccountDeviceNotActive -> "Account device not active."
is VpnException.AccountDeviceNotRegistered -> "Account device not registered."
is VpnException.AccountNotActive -> "Account not active."
is VpnException.AccountReady -> "Account ready"
is VpnException.AccountStatusUnknown -> "Account status unknown."
is VpnException.GatewayException -> "Gateway error"
is VpnException.InternalException -> "Internal error"
is VpnException.InvalidCredential -> "Invalid credential"
is VpnException.InvalidStateException -> "Invalid state exception"
is VpnException.NetworkConnectionException -> "Network connection error"
is VpnException.NoAccountStored -> "Account missing"
is VpnException.NoActiveSubscription -> "No active subscription detected."
is VpnException.OutOfBandwidth -> "Out of bandwidth"
}
}
1 change: 1 addition & 0 deletions nym-vpn-android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<string name="check_faq">Check the FAQ</string>
<string name="join_matrix">Join us on Matrix</string>
<string name="join_discord">Join us on Discord</string>
<string name="create_account_url" translatable="false">https://nymvpn.com/account/create</string>
<string name="matrix_url" translatable="false">https://matrix.to/#/%23NymVPN:nymtech.chat</string>
<string name="discord_url" translatable="false">http://nymtech.net/go/discord</string>
<string name="faq_url" translatable="false">https://support.nymvpn.com</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class NymApi(
}
}

suspend fun getSystemMessages(environment: Tunnel.Environment) : List<SystemMessage> {
suspend fun getSystemMessages(environment: Tunnel.Environment): List<SystemMessage> {
return withContext(ioDispatcher) {
fetchSystemMessages(environment.networkName())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface Backend {

suspend fun getAccountSummary(): AccountStateSummary

suspend fun getAccountLinks(environment: Tunnel.Environment) : AccountLinks
suspend fun getAccountLinks(environment: Tunnel.Environment): AccountLinks

suspend fun storeMnemonic(credential: String)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.nymtech.ipcalculator.AllowedIpCalculator
import net.nymtech.vpn.model.BackendMessage
import net.nymtech.vpn.model.BackendMessage.*
import net.nymtech.vpn.model.Statistics
import net.nymtech.vpn.util.Action
Expand All @@ -30,7 +29,6 @@ import nym_vpn_lib.AccountLinks
import nym_vpn_lib.AccountStateSummary
import nym_vpn_lib.AndroidTunProvider
import nym_vpn_lib.BandwidthEvent
import nym_vpn_lib.ErrorStateReason
import nym_vpn_lib.MixnetEvent
import nym_vpn_lib.TunnelEvent
import nym_vpn_lib.TunnelNetworkSettings
Expand Down Expand Up @@ -98,29 +96,22 @@ class NymBackend private constructor(val context: Context) : Backend, TunnelStat
}
}

@Throws(VpnException::class)
private suspend fun setEnvironment(environment: Tunnel.Environment) {
withContext(ioDispatcher) {
initEnvironment(environment.networkName())
}
}

@Throws(VpnException::class)
override suspend fun getAccountSummary(): AccountStateSummary {
return nym_vpn_lib.getAccountState()
}

@Throws(VpnException::class)
override suspend fun getAccountLinks(environment: Tunnel.Environment) : AccountLinks {
override suspend fun getAccountLinks(environment: Tunnel.Environment): AccountLinks {
return withContext(ioDispatcher) {
fetchAccountLinks(storagePath, environment.networkName(),getCurrentLocaleCountryCode())
fetchAccountLinks(storagePath, environment.networkName(), getCurrentLocaleCountryCode())
}
}

private fun getCurrentLocaleCountryCode() : String {
private fun getCurrentLocaleCountryCode(): String {
return try {
context.resources.configuration.locales.get(0).country.lowercase()
} catch (_ : Exception) {
} catch (_: Exception) {
DEFAULT_LOCALE
}
}
Expand Down Expand Up @@ -152,7 +143,7 @@ class NymBackend private constructor(val context: Context) : Backend, TunnelStat
val service = vpnService.await()
val backend = this@NymBackend
service.setOwner(backend)
runCatching {
try {
startVpn(
VpnConfig(
tunnel.entryPoint,
Expand All @@ -163,20 +154,27 @@ class NymBackend private constructor(val context: Context) : Backend, TunnelStat
backend,
),
)
}.onFailure {
Timber.e(it)
//TODO show error to user
tunnel.onStateChange(Tunnel.State.Down)
} catch (e: VpnException) {
onStartFailure(e)
}
}
}

private fun onStartFailure(e: VpnException) {
Timber.e(e)
onDisconnect()
tunnel?.onStateChange(Tunnel.State.Down)
tunnel?.onBackendMessage(StartFailure(e))
}

override suspend fun stop() {
withContext(ioDispatcher) {
runCatching {
Timber.d("Stopping vpn")
stopVpn()
onVpnShutdown()
}.onFailure {
Timber.e(it)
}
}
}
Expand Down
Loading

0 comments on commit 03b4353

Please sign in to comment.