Merge pull request #2269 from vitorpamplona/claude/fix-relay-connectivity-pJ29t
Improve Tor bootstrap resilience and WebSocket connection handling
This commit is contained in:
+6
@@ -46,10 +46,16 @@ class OkHttpClientFactory(
|
|||||||
.addNetworkInterceptor(keyDecryptor)
|
.addNetworkInterceptor(keyDecryptor)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
private var lastProxy: Proxy? = null
|
||||||
|
|
||||||
fun buildHttpClient(
|
fun buildHttpClient(
|
||||||
proxy: Proxy?,
|
proxy: Proxy?,
|
||||||
timeoutSeconds: Int,
|
timeoutSeconds: Int,
|
||||||
): OkHttpClient {
|
): OkHttpClient {
|
||||||
|
if (proxy != lastProxy) {
|
||||||
|
rootClient.connectionPool.evictAll()
|
||||||
|
lastProxy = proxy
|
||||||
|
}
|
||||||
val seconds = if (proxy != null) timeoutSeconds * 3 else timeoutSeconds
|
val seconds = if (proxy != null) timeoutSeconds * 3 else timeoutSeconds
|
||||||
return rootClient
|
return rootClient
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
|
|||||||
+8
@@ -37,6 +37,7 @@ class OkHttpClientFactoryForRelays(
|
|||||||
const val DEFAULT_IS_MOBILE: Boolean = false
|
const val DEFAULT_IS_MOBILE: Boolean = false
|
||||||
const val DEFAULT_TIMEOUT_ON_WIFI_SECS: Int = 10
|
const val DEFAULT_TIMEOUT_ON_WIFI_SECS: Int = 10
|
||||||
const val DEFAULT_TIMEOUT_ON_MOBILE_SECS: Int = 30
|
const val DEFAULT_TIMEOUT_ON_MOBILE_SECS: Int = 30
|
||||||
|
const val WEBSOCKET_PING_INTERVAL_SECS: Long = 120
|
||||||
|
|
||||||
private fun isEmulator(): Boolean =
|
private fun isEmulator(): Boolean =
|
||||||
Build.FINGERPRINT.startsWith("generic") ||
|
Build.FINGERPRINT.startsWith("generic") ||
|
||||||
@@ -76,10 +77,16 @@ class OkHttpClientFactoryForRelays(
|
|||||||
.addInterceptor(DefaultContentTypeInterceptor(userAgent))
|
.addInterceptor(DefaultContentTypeInterceptor(userAgent))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
private var lastProxy: Proxy? = null
|
||||||
|
|
||||||
fun buildHttpClient(
|
fun buildHttpClient(
|
||||||
proxy: Proxy?,
|
proxy: Proxy?,
|
||||||
timeoutSeconds: Int,
|
timeoutSeconds: Int,
|
||||||
): OkHttpClient {
|
): OkHttpClient {
|
||||||
|
if (proxy != lastProxy) {
|
||||||
|
rootClient.connectionPool.evictAll()
|
||||||
|
lastProxy = proxy
|
||||||
|
}
|
||||||
val seconds = if (proxy != null) timeoutSeconds * 3 else timeoutSeconds
|
val seconds = if (proxy != null) timeoutSeconds * 3 else timeoutSeconds
|
||||||
return rootClient
|
return rootClient
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
@@ -87,6 +94,7 @@ class OkHttpClientFactoryForRelays(
|
|||||||
.connectTimeout(Duration.ofSeconds(seconds.toLong()))
|
.connectTimeout(Duration.ofSeconds(seconds.toLong()))
|
||||||
.readTimeout(Duration.ofSeconds(seconds.toLong() * 3))
|
.readTimeout(Duration.ofSeconds(seconds.toLong() * 3))
|
||||||
.writeTimeout(Duration.ofSeconds(seconds.toLong() * 3))
|
.writeTimeout(Duration.ofSeconds(seconds.toLong() * 3))
|
||||||
|
.pingInterval(Duration.ofSeconds(WEBSOCKET_PING_INTERVAL_SECS))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,34 @@ class TorService(
|
|||||||
private val _status = MutableStateFlow<TorServiceStatus>(TorServiceStatus.Off)
|
private val _status = MutableStateFlow<TorServiceStatus>(TorServiceStatus.Off)
|
||||||
val status: StateFlow<TorServiceStatus> = _status.asStateFlow()
|
val status: StateFlow<TorServiceStatus> = _status.asStateFlow()
|
||||||
|
|
||||||
|
private fun artiDataDir() = File(context.filesDir, "arti")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the Arti cache directory (consensus, relay descriptors) while
|
||||||
|
* preserving the state directory (guard selection). This forces a fresh
|
||||||
|
* consensus download on the next bootstrap, preventing stale cached data
|
||||||
|
* from causing circuit failures.
|
||||||
|
*/
|
||||||
|
private fun clearArtiCache() {
|
||||||
|
val cacheDir = File(artiDataDir(), "cache")
|
||||||
|
if (cacheDir.exists()) {
|
||||||
|
cacheDir.deleteRecursively()
|
||||||
|
Log.d("TorService") { "Cleared Arti cache directory" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all Arti persistent data (state + cache). Used as a last resort
|
||||||
|
* when initialization fails, to recover from corrupted state.
|
||||||
|
*/
|
||||||
|
private fun clearAllArtiData() {
|
||||||
|
val dataDir = artiDataDir()
|
||||||
|
if (dataDir.exists()) {
|
||||||
|
dataDir.deleteRecursively()
|
||||||
|
Log.d("TorService") { "Cleared all Arti data" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the TorClient (once) and start the SOCKS proxy.
|
* Initialize the TorClient (once) and start the SOCKS proxy.
|
||||||
* Must be called from a coroutine on [Dispatchers.IO].
|
* Must be called from a coroutine on [Dispatchers.IO].
|
||||||
@@ -90,12 +118,21 @@ class TorService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataDir = File(context.filesDir, "arti").absolutePath
|
// Clear cached consensus/descriptors so Arti bootstraps with
|
||||||
|
// fresh network data, preventing stale guards/circuits.
|
||||||
|
clearArtiCache()
|
||||||
|
|
||||||
|
val dataDir = artiDataDir().absolutePath
|
||||||
Log.d("TorService") { "Initializing Arti with data dir: $dataDir" }
|
Log.d("TorService") { "Initializing Arti with data dir: $dataDir" }
|
||||||
|
|
||||||
val initResult = ArtiNative.initialize(dataDir)
|
var initResult = ArtiNative.initialize(dataDir)
|
||||||
if (initResult != 0) {
|
if (initResult != 0) {
|
||||||
Log.e("TorService") { "Failed to initialize Arti: error $initResult" }
|
Log.e("TorService") { "Failed to initialize Arti: error $initResult, clearing data and retrying" }
|
||||||
|
clearAllArtiData()
|
||||||
|
initResult = ArtiNative.initialize(dataDir)
|
||||||
|
}
|
||||||
|
if (initResult != 0) {
|
||||||
|
Log.e("TorService") { "Failed to initialize Arti on retry: error $initResult" }
|
||||||
initialized.set(false)
|
initialized.set(false)
|
||||||
_status.value = TorServiceStatus.Off
|
_status.value = TorServiceStatus.Off
|
||||||
return@withContext
|
return@withContext
|
||||||
|
|||||||
+1
-1
@@ -228,7 +228,7 @@ open class BasicRelayClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun dontTryAgainForALongTime() {
|
fun dontTryAgainForALongTime() {
|
||||||
delayToConnectInSeconds = TimeUtils.ONE_DAY
|
delayToConnectInSeconds = TimeUtils.FIVE_MINUTES
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendOrConnectAndSync(cmd: Command) {
|
override fun sendOrConnectAndSync(cmd: Command) {
|
||||||
|
|||||||
Reference in New Issue
Block a user