mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-09 08:04:45 +00:00
Merge pull request #3223 from vitorpamplona/fix/gate-tor-relays-until-ready
Gate Tor-routed relay dials until Tor is ready
This commit is contained in:
@@ -427,10 +427,19 @@ class AppModules(
|
||||
|
||||
// Connects the INostrClient class with okHttp
|
||||
val websocketBuilder =
|
||||
OkHttpWebSocket.Builder { url ->
|
||||
val useTor = torEvaluatorFlow.shouldUseTorForRelay(url)
|
||||
okHttpClientForRelays.getHttpClient(useTor)
|
||||
}
|
||||
OkHttpWebSocket.Builder(
|
||||
httpClient = { url ->
|
||||
val useTor = torEvaluatorFlow.shouldUseTorForRelay(url)
|
||||
okHttpClientForRelays.getHttpClient(useTor)
|
||||
},
|
||||
// Don't dial Tor-routed relays until Tor's SOCKS port is up. Otherwise the
|
||||
// whole Tor-routed relay set is hammered with doomed dials against the dead
|
||||
// proxy during bootstrap. RelayProxyClientConnector reconnects them (with
|
||||
// ignoreRetryDelays=true) the instant Tor flips to Active.
|
||||
canDial = { url ->
|
||||
!torEvaluatorFlow.shouldUseTorForRelay(url) || torManager.isSocksReady()
|
||||
},
|
||||
)
|
||||
|
||||
// Caches all events in Memory
|
||||
val cache: LocalCache = LocalCache
|
||||
|
||||
@@ -133,12 +133,16 @@ class OkHttpWebSocket(
|
||||
|
||||
class Builder(
|
||||
val httpClient: (NormalizedRelayUrl) -> OkHttpClient,
|
||||
val canDial: (NormalizedRelayUrl) -> Boolean = { true },
|
||||
) : WebsocketBuilder {
|
||||
// Called when connecting.
|
||||
override fun build(
|
||||
url: NormalizedRelayUrl,
|
||||
out: WebSocketListener,
|
||||
) = OkHttpWebSocket(url, httpClient, out)
|
||||
|
||||
// Gates the dial — false skips it (e.g. a Tor-routed relay before Tor is ready).
|
||||
override fun canConnect(url: NormalizedRelayUrl) = canDial(url)
|
||||
}
|
||||
|
||||
override fun disconnect() {
|
||||
|
||||
+8
-1
@@ -27,7 +27,9 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlin.concurrent.Volatile
|
||||
import kotlin.test.Test
|
||||
@@ -87,7 +89,12 @@ class RelayHealthStoreCloseTest {
|
||||
ioDispatcher = dispatcher,
|
||||
)
|
||||
|
||||
advanceUntilIdle()
|
||||
// NB: the store's init launches an always-on `while(true){ reclassify(); delay(60s) }`
|
||||
// ticker on this shared test scheduler. advanceUntilIdle() would chase that periodic
|
||||
// delay forever (livelock). Advance just past the persist debounce instead so init's
|
||||
// debounced save fires while the ticker stays parked at its 60s mark.
|
||||
advanceTimeBy(RelayHealthStore.PERSIST_DEBOUNCE_MS + 1)
|
||||
runCurrent()
|
||||
val baseline = persistence.saves
|
||||
|
||||
store.close()
|
||||
|
||||
+6
@@ -103,6 +103,12 @@ open class BasicRelayClient(
|
||||
override fun needsToReconnect() = socket?.needsReconnect() ?: true
|
||||
|
||||
override fun connect() {
|
||||
// Transport gate: skip the dial when the builder reports this relay's transport
|
||||
// isn't ready (e.g. a Tor-routed relay while Tor's SOCKS port isn't up). Returning
|
||||
// here before the mutex/socket/onConnecting means no doomed dial and no backoff
|
||||
// growth; a later reconnect pass (fired when the transport becomes ready) will dial.
|
||||
if (!socketBuilder.canConnect(url)) return
|
||||
|
||||
// If there is a connection, don't wait.
|
||||
if (connectingMutex.exchange(true)) {
|
||||
return
|
||||
|
||||
+15
@@ -27,4 +27,19 @@ interface WebsocketBuilder {
|
||||
url: NormalizedRelayUrl,
|
||||
out: WebSocketListener,
|
||||
): WebSocket
|
||||
|
||||
/**
|
||||
* Whether the transport for [url] is ready to dial right now. Returning false makes
|
||||
* [com.vitorpamplona.quartz.nip01Core.relay.client.single.basic.BasicRelayClient.connect]
|
||||
* skip the dial entirely — no socket, no backoff growth — until a later reconnect pass
|
||||
* finds it ready.
|
||||
*
|
||||
* The motivating case: a Tor-routed relay while Tor's SOCKS proxy isn't up yet. Without
|
||||
* this gate the pool hammers the dead proxy with doomed dials during the whole Tor
|
||||
* bootstrap window. The caller is responsible for re-triggering a reconnect once the
|
||||
* transport becomes ready (e.g. on the Tor status flipping to Active).
|
||||
*
|
||||
* Defaults to true so non-proxied builders need no change.
|
||||
*/
|
||||
fun canConnect(url: NormalizedRelayUrl): Boolean = true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user