From d1bd5734cdcec7362f81e1e3576377affca07021 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 11 Jun 2026 13:34:49 -0400 Subject: [PATCH] fix(relay): rebuild sockets opened on the wrong transport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit connectAndSyncFiltersIfDisconnected() bailed whenever a socket already existed, so a still-connecting socket built for the wrong transport (e.g. a relay whose Tor classification changed since the dial started) could never be preempted — it blocked until the hung dial timed out. The connected-relay path in RelayPool.reconnectIfNeedsTo already rebuilds ready sockets via needsToReconnect(); this covers the connecting state it cannot see (isConnectionStarted() true but isConnected() false). Now: if a socket exists but reports needsReconnect() (transport/proxy mismatch against the current builder decision), drop it and redial on the correct transport; otherwise leave it. Disconnected relays still honor their reconnect backoff. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../client/single/basic/BasicRelayClient.kt | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt index 33877f0f88..d1159083b6 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClient.kt @@ -212,12 +212,27 @@ open class BasicRelayClient( } override fun connectAndSyncFiltersIfDisconnected(ignoreRetryDelays: Boolean) { - if (!isConnectionStarted() && !connectingMutex.load()) { - // waits 60 seconds to reconnect after disconnected. - if (ignoreRetryDelays || TimeUtils.now() > lastConnectTentativeInSeconds + delayToConnectInSeconds) { - upRelayDelayToConnect() + if (connectingMutex.load()) return + + if (isConnectionStarted()) { + // A socket already exists. Normally leave it alone, but if it was opened for the wrong + // transport — e.g. the relay's Tor classification changed since (a clearnet relay now routed + // through the Tor proxy, or vice-versa) — tear it down and rebuild on the current transport. + // Without this an in-flight dial on the wrong transport can never be preempted: a still- + // connecting socket leaves isConnectionStarted() true (so the old guard skipped it) yet + // isConnected() false (so RelayPool.reconnectIfNeedsTo's connected-relay branch never runs), + // and the request blocks until that hung dial finally times out. + if (socket?.needsReconnect() == true) { + disconnect() connect() } + return + } + + // waits 60 seconds to reconnect after disconnected. + if (ignoreRetryDelays || TimeUtils.now() > lastConnectTentativeInSeconds + delayToConnectInSeconds) { + upRelayDelayToConnect() + connect() } }