diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt index 347f8537b0..7814e880f6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/AppModules.kt @@ -475,9 +475,10 @@ class AppModules( val relayProxyClientConnector = RelayProxyClientConnector( torEvaluatorFlow.flow, - okHttpClientForRelays, - connManager, - torManager, + okHttpClientForRelays.defaultHttpClient, + okHttpClientForRelays.defaultHttpClientWithoutProxy, + connManager.status, + torManager.status, client, applicationIOScope, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayProxyClientConnector.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayProxyClientConnector.kt index 7f7ad3eee0..69c9b0b9e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayProxyClientConnector.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/RelayProxyClientConnector.kt @@ -21,10 +21,7 @@ package com.vitorpamplona.amethyst.service.relayClient import com.vitorpamplona.amethyst.model.torState.TorRelayEvaluation -import com.vitorpamplona.amethyst.service.connectivity.ConnectivityManager import com.vitorpamplona.amethyst.service.connectivity.ConnectivityStatus -import com.vitorpamplona.amethyst.service.okhttp.DualHttpClientManagerForRelays -import com.vitorpamplona.amethyst.ui.tor.TorManager import com.vitorpamplona.amethyst.ui.tor.TorServiceStatus import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.utils.Log @@ -44,9 +41,10 @@ import okhttp3.OkHttpClient class RelayProxyClientConnector( val torEvaluator: StateFlow, - val okHttpClients: DualHttpClientManagerForRelays, - val connManager: ConnectivityManager, - val torManager: TorManager, + val torConnection: StateFlow, + val clearConnection: StateFlow, + val connectivityStatus: StateFlow, + val torStatus: StateFlow, val client: INostrClient, val scope: CoroutineScope, ) { @@ -58,14 +56,21 @@ class RelayProxyClientConnector( val torStatus: TorServiceStatus, ) + // The OkHttp clients in use the last time we forced a reconnect. These are only + // rebuilt when something connection-relevant changes (Tor's SOCKS port appears, + // wifi<->cellular switch), so comparing them tells us whether a wakeup is a real + // transport change or just noise (Tor bootstrap status churn, connectivity blips). + private var lastTorConnection: OkHttpClient? = null + private var lastClearConnection: OkHttpClient? = null + @OptIn(FlowPreview::class) val relayServices = combine( torEvaluator, - okHttpClients.defaultHttpClient, - okHttpClients.defaultHttpClientWithoutProxy, - connManager.status, - torManager.status, + torConnection, + clearConnection, + connectivityStatus, + torStatus, ) { torSettings, torConnection, clearConnection, connectivity, torStatus -> RelayServiceInfra(torSettings, torConnection, clearConnection, connectivity, torStatus) }.debounce(100) @@ -97,10 +102,19 @@ class RelayProxyClientConnector( } else -> { - Log.d("ManageRelayServices", "Relay Services have changed, reconnecting relays that need to") + // Only skip the per-relay exponential backoff when the actual HTTP + // transport changed. Otherwise (e.g. Tor still bootstrapping, the SOCKS + // port not yet listening) honor each relay's backoff so we don't + // reconnect-fail-reconnect on every unrelated infrastructure event. + val transportChanged = + it.torConnection !== lastTorConnection || it.clearConnection !== lastClearConnection + lastTorConnection = it.torConnection + lastClearConnection = it.clearConnection + + Log.d("ManageRelayServices", "Relay Services have changed, reconnecting relays that need to (transportChanged=$transportChanged)") client.reconnect( onlyIfChanged = true, - ignoreRetryDelays = true, + ignoreRetryDelays = transportChanged, ) } }