From 261242e7b6b7f62642427bb9b43b7506777ab992 Mon Sep 17 00:00:00 2001 From: "sergei.bakhtiarov" Date: Mon, 9 Feb 2026 20:33:00 +0100 Subject: [PATCH] feat: reconnect socket when closed normally (WPB-21876) --- .../logic/data/event/EventRepository.kt | 7 ++++- .../logic/data/event/EventRepositoryTest.kt | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/EventRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/EventRepository.kt index b0e009557c6..26981e88b86 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/EventRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/EventRepository.kt @@ -353,9 +353,14 @@ internal class EventDataSource( ) } + @Suppress("ThrowsCount") private suspend fun handleWebSocketClosure(webSocketEvent: WebSocketEvent.Close) { when (val cause = webSocketEvent.cause) { - null -> logger.i("Websocket closed normally") + null -> { + logger.i("Websocket closed normally, will retry to keep connection alive") + throw KaliumSyncException("Websocket closed normally", CoreFailure.Unknown(null)) + } + is IOException -> throw KaliumSyncException("Websocket disconnected", NetworkFailure.NoNetworkConnection(cause)) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/event/EventRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/event/EventRepositoryTest.kt index 1d61d8e942e..98b4757f560 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/event/EventRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/event/EventRepositoryTest.kt @@ -585,6 +585,32 @@ class EventRepositoryTest { } } + @Test + fun givenWebSocketClosedWithNullCause_whenHandlingClosure_thenShouldThrowKaliumSyncException() = runTest { + val (_, repository) = Arrangement() + .withClientHasConsumableNotifications(true) + .withCurrentClientIdReturning(TestClient.CLIENT_ID) + .withConsumeLiveEventsReturning( + NetworkResponse.Success( + value = flowOf(WebSocketEvent.Close(cause = null)), + headers = emptyMap(), + httpCode = 200 + ) + ) + .arrange() + + val eitherFlow = repository.liveEvents() + assertTrue(eitherFlow is Either.Right) + + val flow = eitherFlow.value + + val thrown = assertFailsWith { + flow.collect {} + } + + assertIs(thrown.coreFailureCause) + } + private companion object { const val LAST_SAVED_EVENT_ID_KEY = "last_processed_event_id" val MEMBER_JOIN_EVENT = EventContentDTO.Conversation.MemberJoinDTO(