diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index cddab9ea..2fbae5e0 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -553,6 +553,7 @@ Broker host is empty Connection failed Connection lost + Couldn't reach %1$s:%2$d. Check your network or pick another broker in Settings → Jam. Broker diff --git a/composeApp/src/commonMain/kotlin/org/spotube/spotube/core/jam/JamRoomClient.kt b/composeApp/src/commonMain/kotlin/org/spotube/spotube/core/jam/JamRoomClient.kt index 85085f0f..07810202 100644 --- a/composeApp/src/commonMain/kotlin/org/spotube/spotube/core/jam/JamRoomClient.kt +++ b/composeApp/src/commonMain/kotlin/org/spotube/spotube/core/jam/JamRoomClient.kt @@ -33,12 +33,14 @@ import org.spotube.spotube.modules.settings.JamBroker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -47,6 +49,7 @@ import kotlinx.serialization.json.Json import org.jetbrains.compose.resources.getString import spotube.composeapp.generated.resources.Res import spotube.composeapp.generated.resources.jam_error_broker_host_empty +import spotube.composeapp.generated.resources.jam_error_broker_unreachable import spotube.composeapp.generated.resources.jam_error_connection_failed import spotube.composeapp.generated.resources.jam_error_connection_lost import spotube.composeapp.generated.resources.jam_error_no_broker @@ -135,8 +138,15 @@ class JamRoomClient : KoinComponent { val mqtt = startClient(broker, clientId) client = mqtt - withTimeout(broker.connectionTimeoutSeconds.seconds) { - mqtt.awaitConnectivity() + try { + withTimeout(broker.connectionTimeoutSeconds.seconds) { + // connectionState replays its current value, unlike awaitConnectivity's + // broadcast flow, which loses a CONNACK that lands before it is collected. + mqtt.connectionState.first { it is ConnectionState.Connected } + } + } catch (e: TimeoutCancellationException) { + throw IllegalStateException( + getString(Res.string.jam_error_broker_unreachable, broker.host, broker.port), e) } _connectionError.value = null log.i { "Connected to ${broker.host}:${broker.port} room=$code as $clientId" } diff --git a/composeApp/src/commonMain/kotlin/org/spotube/spotube/modules/settings/SettingsModels.kt b/composeApp/src/commonMain/kotlin/org/spotube/spotube/modules/settings/SettingsModels.kt index f22688a3..90f87e3e 100644 --- a/composeApp/src/commonMain/kotlin/org/spotube/spotube/modules/settings/SettingsModels.kt +++ b/composeApp/src/commonMain/kotlin/org/spotube/spotube/modules/settings/SettingsModels.kt @@ -98,9 +98,9 @@ data class UserSettings( @Serializable data class JamBroker( val name: String = "", - val host: String = "test.mosquitto.org", - val port: Int = 1883, - val useTls: Boolean = false, + val host: String = "broker.hivemq.com", + val port: Int = 8883, + val useTls: Boolean = true, val username: String? = null, val password: String? = null, val clientIdPrefix: String = "spotube",