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 5992cecdba..b495d42dbb 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 @@ -136,7 +136,9 @@ open class BasicRelayClient( socket?.connect() } catch (e: Exception) { if (e is CancellationException) throw e - listener.onCannotConnect(this, "Error when trying to connect: ${e.message ?: e::class.simpleName}") + val typeName = e::class.simpleName + val detail = e.message?.let { "$it ($typeName)" } ?: (typeName ?: "unknown error") + listener.onCannotConnect(this, "Error when trying to connect: $detail") listener.onDisconnected(this) dontTryAgainForALongTime() markConnectionAsClosed() @@ -187,9 +189,15 @@ open class BasicRelayClient( } else { socket?.disconnect() - // suppression rules below must match the raw message; displayMsg is for listener output only + // suppression rules below must match the raw message; displayMsg is for listener output only. + // Always include the exception's class name: message text is + // localized and inconsistent across platforms, but the type + // (SocketTimeoutException / UnknownHostException / SSLHandshakeException / + // ConnectException …) is stable and lets listeners classify a failure + // reliably — a busy relay (timeout) vs a dead one (bad domain / TLS). val msg = t.message - val displayMsg = msg ?: t::class.simpleName + val typeName = t::class.simpleName + val displayMsg = if (msg != null) "$msg ($typeName)" else (typeName ?: "unknown error") // checks if this is an actual failure. Closing the socket generates an onFailure as well. // ignore tor errors. diff --git a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClientTest.kt b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClientTest.kt index 065ef0fcaf..7a7caaec58 100644 --- a/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClientTest.kt +++ b/quartz/src/commonTest/kotlin/com/vitorpamplona/quartz/nip01Core/relay/client/single/basic/BasicRelayClientTest.kt @@ -72,13 +72,15 @@ class BasicRelayClientTest { } @Test - fun onFailureWithMessageKeepsExistingFormat() { + fun onFailureWithMessageAppendsExceptionClassName() { val (socket, listener) = connectAndCapture() socket.onFailure(Exception("Connection reset"), null, null) + // The exception type is appended so listeners can classify the failure by + // its stable class name rather than by localized message text. assertEquals( - listOf("WebSocket Failure: Connection reset"), + listOf("WebSocket Failure: Connection reset (Exception)"), listener.cannotConnectMessages, ) }