Detect and recycle WebSockets stuck in connecting state.

This commit is contained in:
Cody Henthorne
2025-05-16 13:13:32 -04:00
committed by GitHub
parent b6c033b075
commit a2f7afcb68
8 changed files with 57 additions and 14 deletions

View File

@@ -7,9 +7,16 @@ package org.thoughtcrime.securesms.net
import io.reactivex.rxjava3.kotlin.subscribeBy
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.net.SignalWebSocketHealthMonitor.Companion.KEEP_ALIVE_SEND_CADENCE
import org.thoughtcrime.securesms.net.SignalWebSocketHealthMonitor.Companion.KEEP_ALIVE_TIMEOUT
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.api.util.SleepTimer
import org.whispersystems.signalservice.api.websocket.HealthMonitor
@@ -49,6 +56,10 @@ class SignalWebSocketHealthMonitor(
private var needsKeepAlive = false
private var lastKeepAliveReceived: Duration = 0.seconds
private val scope = CoroutineScope(Dispatchers.IO)
private var connectingTimeoutJob: Job? = null
private var failedInConnecting: Boolean = false
@Suppress("CheckResult")
fun monitor(webSocket: SignalWebSocket) {
executor.execute {
@@ -69,11 +80,22 @@ class SignalWebSocketHealthMonitor(
private fun onStateChanged(connectionState: WebSocketConnectionState) {
executor.execute {
Log.v(TAG, "${webSocket?.connectionName} onStateChange($connectionState)")
when (connectionState) {
WebSocketConnectionState.CONNECTING -> {
connectingTimeoutJob?.cancel()
connectingTimeoutJob = scope.launch {
delay(if (failedInConnecting) 60.seconds else 30.seconds)
Log.w(TAG, "${webSocket?.connectionName} Did not leave CONNECTING state, starting over")
onConnectingTimeout()
}
}
WebSocketConnectionState.CONNECTED -> {
if (webSocket is SignalWebSocket.AuthenticatedWebSocket) {
TextSecurePreferences.setUnauthorizedReceived(AppDependencies.application, false)
}
failedInConnecting = false
}
WebSocketConnectionState.AUTHENTICATION_FAILED -> {
if (webSocket is SignalWebSocket.AuthenticatedWebSocket) {
@@ -91,6 +113,13 @@ class SignalWebSocketHealthMonitor(
needsKeepAlive = connectionState == WebSocketConnectionState.CONNECTED
if (connectionState != WebSocketConnectionState.CONNECTING) {
connectingTimeoutJob?.let {
it.cancel()
connectingTimeoutJob = null
}
}
updateKeepAliveSenderStatus()
}
}
@@ -112,6 +141,13 @@ class SignalWebSocketHealthMonitor(
}
}
private fun onConnectingTimeout() {
executor.execute {
webSocket?.forceNewWebSocket()
failedInConnecting = true
}
}
private fun updateKeepAliveSenderStatus() {
if (keepAliveSender == null && sendKeepAlives()) {
keepAliveSender = KeepAliveSender().also { it.start() }