diff --git a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/CallManagerImpl.kt b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/CallManagerImpl.kt index b76b3df56b8..693c76d98f9 100644 --- a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/CallManagerImpl.kt +++ b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/feature/call/CallManagerImpl.kt @@ -78,6 +78,8 @@ import com.wire.kalium.logic.feature.call.usecase.GetCallConversationTypeProvide import com.wire.kalium.logic.feature.message.MessageSender import com.wire.kalium.logic.featureFlags.KaliumConfigs import com.wire.kalium.logic.functional.fold +import com.wire.kalium.logic.util.ServerTimeHandler +import com.wire.kalium.logic.util.ServerTimeHandlerImpl import com.wire.kalium.logic.util.toInt import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.util.KaliumDispatcher @@ -119,6 +121,7 @@ class CallManagerImpl internal constructor( private val flowManagerService: FlowManagerService, private val json: Json = Json { ignoreUnknownKeys = true }, private val shouldRemoteMuteChecker: ShouldRemoteMuteChecker = ShouldRemoteMuteCheckerImpl(), + private val serverTimeHandler: ServerTimeHandler = ServerTimeHandlerImpl(), kaliumDispatchers: KaliumDispatcher = KaliumDispatcherImpl ) : CallManager { @@ -255,8 +258,6 @@ class CallManagerImpl internal constructor( ) if (callingValue.type != REMOTE_MUTE_TYPE || shouldRemoteMute) { - val currTime = System.currentTimeMillis() - val targetConversationId = if (message.isSelfMessage) { content.conversationId ?: message.conversationId } else { @@ -270,7 +271,7 @@ class CallManagerImpl internal constructor( inst = deferredHandle.await(), msg = msg, len = msg.size, - curr_time = Uint32_t(value = currTime / 1000), + curr_time = Uint32_t(value = serverTimeHandler.toServerTimestamp()), msg_time = Uint32_t(value = message.date.epochSeconds), convId = federatedIdMapper.parseToFederatedId(targetConversationId), userId = federatedIdMapper.parseToFederatedId(message.senderUserId), diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/Event.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/Event.kt index ab0f10ef26a..8a580fd5514 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/Event.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/event/Event.kt @@ -57,7 +57,7 @@ import kotlinx.serialization.json.JsonNull */ data class EventEnvelope( val event: Event, - val deliveryInfo: EventDeliveryInfo, + val deliveryInfo: EventDeliveryInfo ) { override fun toString(): String { return super.toString() 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 2667e517b9f..b00c02e908f 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 @@ -85,6 +85,7 @@ interface EventRepository { * @return Either containing a [CoreFailure] or the oldest available event ID as a String. */ suspend fun fetchOldestAvailableEventId(): Either + suspend fun fetchServerTime(): String? } class EventDataSource( @@ -193,6 +194,15 @@ class EventDataSource( } }.map { it.id } + override suspend fun fetchServerTime(): String? { + val result = notificationApi.getServerTime(NOTIFICATIONS_QUERY_SIZE) + return if (result.isSuccessful()) { + result.value + } else { + null + } + } + private companion object { const val NOTIFICATIONS_QUERY_SIZE = 100 const val LAST_PROCESSED_EVENT_ID_KEY = "last_processed_event_id" diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 99e714d93db..e21c54ba9b1 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -918,24 +918,23 @@ class UserSessionScope internal constructor( kaliumFileSystem = kaliumFileSystem ) - private val eventGatherer: EventGatherer - get() = EventGathererImpl( - eventRepository, - incrementalSyncRepository, - userScopedLogger, - ) + private val eventGatherer: EventGatherer get() = EventGathererImpl( + eventRepository = eventRepository, + incrementalSyncRepository = incrementalSyncRepository, + logger = userScopedLogger + ) private val eventProcessor: EventProcessor by lazy { EventProcessorImpl( - eventRepository, - conversationEventReceiver, - userEventReceiver, - teamEventReceiver, - featureConfigEventReceiver, - userPropertiesEventReceiver, - federationEventReceiver, - this@UserSessionScope, - userScopedLogger, + eventRepository = eventRepository, + conversationEventReceiver = conversationEventReceiver, + userEventReceiver = userEventReceiver, + teamEventReceiver = teamEventReceiver, + featureConfigEventReceiver = featureConfigEventReceiver, + userPropertiesEventReceiver = userPropertiesEventReceiver, + federationEventReceiver = federationEventReceiver, + processingScope = this@UserSessionScope, + logger = userScopedLogger, ) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/incremental/EventGatherer.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/incremental/EventGatherer.kt index 8e9ce00fb45..707cbcbcace 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/incremental/EventGatherer.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/incremental/EventGatherer.kt @@ -34,6 +34,8 @@ import com.wire.kalium.logic.functional.onFailure import com.wire.kalium.logic.functional.onSuccess import com.wire.kalium.logic.kaliumLogger import com.wire.kalium.logic.sync.KaliumSyncException +import com.wire.kalium.logic.util.ServerTimeHandler +import com.wire.kalium.logic.util.ServerTimeHandlerImpl import com.wire.kalium.network.api.base.authenticated.notification.WebSocketEvent import com.wire.kalium.network.exceptions.KaliumException import io.ktor.http.HttpStatusCode @@ -52,6 +54,7 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.transformWhile +import kotlinx.datetime.toInstant /** * Responsible for fetching events from a remote source, orchestrating between events missed since @@ -77,6 +80,7 @@ internal interface EventGatherer { internal class EventGathererImpl( private val eventRepository: EventRepository, private val incrementalSyncRepository: IncrementalSyncRepository, + private val serverTimeHandler: ServerTimeHandler = ServerTimeHandlerImpl(), logger: KaliumLogger = kaliumLogger, ) : EventGatherer { @@ -165,6 +169,7 @@ internal class EventGathererImpl( private suspend fun FlowCollector.onWebSocketOpen() { logger.i("Websocket Open") + handleTimeDrift() eventRepository .pendingEvents() .onEach { result -> @@ -181,6 +186,12 @@ internal class EventGathererImpl( _currentSource.value = EventSource.LIVE } + private suspend fun handleTimeDrift() { + eventRepository.fetchServerTime()?.let { + serverTimeHandler.computeTimeOffset(it.toInstant().epochSeconds) + } + } + private fun throwPendingEventException(failure: CoreFailure) { val networkCause = (failure as? NetworkFailure.ServerMiscommunication)?.rootCause val isEventNotFound = networkCause is KaliumException.InvalidRequestError diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/util/ServerTimeHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/util/ServerTimeHandler.kt new file mode 100644 index 00000000000..53e7f5177ce --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/util/ServerTimeHandler.kt @@ -0,0 +1,54 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.util + +import com.wire.kalium.logic.kaliumLogger +import kotlinx.datetime.Clock + +internal interface ServerTimeHandler { + fun computeTimeOffset(serverTime: Long) + fun toServerTimestamp(localTimestamp: Long = Clock.System.now().epochSeconds): Long +} + +internal class ServerTimeHandlerImpl : ServerTimeHandler { + + /** + * Used to store the difference (offset) between the server time and the local client time. + * And it will be used to adjust timestamps between server and client times. + */ + private var timeOffset: Long = 0 + + /** + * Compute the time offset between the server and the client + * @param serverTime the server time to compute the offset + */ + override fun computeTimeOffset(serverTime: Long) { + kaliumLogger.i("ServerTimeHandler: computing time offset between server and client..") + val offset = Clock.System.now().epochSeconds - serverTime + timeOffset = offset + } + + /** + * Convert local timestamp to server timestamp + * @param localTimestamp timestamp from client to convert + * @return the timestamp adjusted with the client/server time shift + */ + override fun toServerTimestamp(localTimestamp: Long): Long { + return localTimestamp - timeOffset + } +} 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 04e8e4a38c2..ddff0e1063b 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 @@ -52,6 +52,8 @@ import kotlinx.datetime.Instant import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertIs +import kotlin.test.assertNotNull +import kotlin.test.assertNull class EventRepositoryTest { @@ -136,6 +138,34 @@ class EventRepositoryTest { } } + @Test + fun givenAPIFailure_whenFetchingServerTime_thenReturnNull() = runTest { + val (_, eventRepository) = Arrangement() + .withGetServerTimeReturning(NetworkResponse.Error(KaliumException.NoNetwork())) + .arrange() + + val result = eventRepository.fetchServerTime() + + assertNull(result) + } + + + @Test + fun givenAPISucceeds_whenFetchingServerTime_thenReturnTime() = runTest { + val result = NetworkResponse.Success( + value = "123434545", + headers = mapOf(), + httpCode = HttpStatusCode.OK.value + ) + val (_, eventRepository) = Arrangement() + .withGetServerTimeReturning(result) + .arrange() + + val time = eventRepository.fetchServerTime() + + assertNotNull(time) + } + private companion object { const val LAST_PROCESSED_EVENT_ID_KEY = "last_processed_event_id" } @@ -158,12 +188,6 @@ class EventRepositoryTest { } } - suspend fun withDeleteMetadataSucceeding() = apply { - coEvery { - metaDAO.deleteValue(any()) - }.returns(Unit) - } - suspend fun withLastStoredEventId(value: String?) = apply { coEvery { metaDAO.valueByKey(LAST_PROCESSED_EVENT_ID_KEY) @@ -176,15 +200,15 @@ class EventRepositoryTest { }.returns(result) } - suspend fun withLastNotificationRemote(result: NetworkResponse) = apply { + suspend fun withOldestNotificationReturning(result: NetworkResponse) = apply { coEvery { - notificationApi.mostRecentNotification(any()) + notificationApi.oldestNotification(any()) }.returns(result) } - suspend fun withOldestNotificationReturning(result: NetworkResponse) = apply { + suspend fun withGetServerTimeReturning(result: NetworkResponse) = apply { coEvery { - notificationApi.oldestNotification(any()) + notificationApi.getServerTime(any()) }.returns(result) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestEvent.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestEvent.kt index 48cde9de04f..4c3e4f1cec6 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestEvent.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestEvent.kt @@ -249,7 +249,10 @@ object TestEvent { id = "eventId", ) - fun Event.wrapInEnvelope(isTransient: Boolean = false, source: EventSource = EventSource.LIVE): EventEnvelope { + fun Event.wrapInEnvelope( + isTransient: Boolean = false, + source: EventSource = EventSource.LIVE + ): EventEnvelope { return EventEnvelope(this, EventDeliveryInfo(isTransient, source)) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/EventGathererTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/EventGathererTest.kt index dc0b1451608..4ae56bb468a 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/EventGathererTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/EventGathererTest.kt @@ -30,10 +30,12 @@ import com.wire.kalium.logic.framework.TestEvent import com.wire.kalium.logic.framework.TestEvent.wrapInEnvelope import com.wire.kalium.logic.functional.Either import com.wire.kalium.logic.sync.KaliumSyncException +import com.wire.kalium.logic.util.ServerTimeHandler import com.wire.kalium.network.api.base.authenticated.notification.WebSocketEvent import com.wire.kalium.network.api.model.ErrorResponse import com.wire.kalium.network.exceptions.KaliumException import io.mockative.Mock +import io.mockative.any import io.mockative.coEvery import io.mockative.coVerify import io.mockative.every @@ -66,6 +68,7 @@ class EventGathererTest { .withPendingEventsReturning(emptyFlow()) .withKeepAliveConnectionPolicy() .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning("2022-03-30T15:36:00.000Z") .arrange() eventGatherer.gatherEvents().test { @@ -82,6 +85,10 @@ class EventGathererTest { arrangement.eventRepository.pendingEvents() }.wasInvoked(exactly = once) + coVerify { + arrangement.serverTimeHandler.computeTimeOffset(any()) + }.wasInvoked(exactly = once) + cancelAndIgnoreRemainingEvents() } } @@ -95,6 +102,7 @@ class EventGathererTest { .withPendingEventsReturning(emptyFlow()) .withConnectionPolicyReturning(MutableStateFlow(ConnectionPolicy.DISCONNECT_AFTER_PENDING_EVENTS)) .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() eventGatherer.gatherEvents().test { @@ -125,6 +133,7 @@ class EventGathererTest { .withPendingEventsReturning(flowOf(Either.Right(pendingEvent))) .withConnectionPolicyReturning(MutableStateFlow(ConnectionPolicy.DISCONNECT_AFTER_PENDING_EVENTS)) .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() eventGatherer.gatherEvents().test { @@ -157,6 +166,7 @@ class EventGathererTest { .withPendingEventsReturning(emptyFlow()) .withConnectionPolicyReturning(MutableStateFlow(ConnectionPolicy.KEEP_ALIVE)) .withLiveEventsReturning(Either.Right(liveEventsChannel)) + .withFetchServerTimeReturning(null) .arrange() eventGatherer.gatherEvents().test { @@ -171,11 +181,12 @@ class EventGathererTest { fun givenWebsocketEventAndDisconnectPolicy_whenGathering_thenShouldCompleteFlow() = runTest { val liveEventsChannel = Channel>(capacity = Channel.UNLIMITED) - val (arrangement, eventGatherer) = Arrangement() + val (_, eventGatherer) = Arrangement() .withLastEventIdReturning(Either.Right("lastEventId")) .withPendingEventsReturning(emptyFlow()) .withConnectionPolicyReturning(MutableStateFlow(ConnectionPolicy.DISCONNECT_AFTER_PENDING_EVENTS)) .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() // Open Websocket should trigger fetching pending events @@ -198,6 +209,7 @@ class EventGathererTest { .withPendingEventsReturning(emptyFlow()) .withKeepAliveConnectionPolicy() .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() eventGatherer.gatherEvents().test { @@ -222,6 +234,7 @@ class EventGathererTest { .withPendingEventsReturning(emptyFlow()) .withConnectionPolicyReturning(MutableStateFlow(ConnectionPolicy.DISCONNECT_AFTER_PENDING_EVENTS)) .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() eventGatherer.gatherEvents().test { @@ -248,6 +261,7 @@ class EventGathererTest { .withPendingEventsReturning(flowOf(Either.Left(failureCause))) .withKeepAliveConnectionPolicy() .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() eventGatherer.gatherEvents().test { @@ -272,6 +286,7 @@ class EventGathererTest { .withPendingEventsReturning(flowOf(Either.Left(failureCause))) .withKeepAliveConnectionPolicy() .withLiveEventsReturning(Either.Right(liveEventsChannel.receiveAsFlow())) + .withFetchServerTimeReturning(null) .arrange() eventGatherer.gatherEvents().test { @@ -293,6 +308,7 @@ class EventGathererTest { .withPendingEventsReturning(emptyFlow()) .withKeepAliveConnectionPolicy() .withLiveEventsReturning(Either.Right(emptyFlow())) + .withFetchServerTimeReturning(null) .arrange() eventGatherer.gatherEvents().test { @@ -315,6 +331,7 @@ class EventGathererTest { .withPendingEventsReturning(flowOf(Either.Right(event))) .withKeepAliveConnectionPolicy() .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() // Open Websocket should trigger fetching pending events @@ -337,6 +354,7 @@ class EventGathererTest { .withPendingEventsReturning(emptyFlow()) .withKeepAliveConnectionPolicy() .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() // Open Websocket should trigger fetching pending events @@ -362,6 +380,7 @@ class EventGathererTest { .withPendingEventsReturning(flowOf(Either.Right(event))) .withKeepAliveConnectionPolicy() .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() // Open Websocket should trigger fetching pending events @@ -397,6 +416,7 @@ class EventGathererTest { .withPendingEventsReturning(flowOf(Either.Left(failureCause))) .withKeepAliveConnectionPolicy() .withLiveEventsReturning(Either.Right(liveEventsChannel.consumeAsFlow())) + .withFetchServerTimeReturning(null) .arrange() eventGatherer.gatherEvents().test { @@ -419,7 +439,10 @@ class EventGathererTest { @Mock val incrementalSyncRepository = mock(IncrementalSyncRepository::class) - val eventGatherer: EventGatherer = EventGathererImpl(eventRepository, incrementalSyncRepository) + @Mock + val serverTimeHandler = mock(ServerTimeHandler::class) + + val eventGatherer: EventGatherer = EventGathererImpl(eventRepository, incrementalSyncRepository, serverTimeHandler) suspend fun withLiveEventsReturning(either: Either>>) = apply { coEvery { @@ -427,6 +450,12 @@ class EventGathererTest { }.returns(either) } + suspend fun withFetchServerTimeReturning(time: String?) = apply { + coEvery { + eventRepository.fetchServerTime() + }.returns(time) + } + suspend fun withPendingEventsReturning(either: Flow>) = apply { coEvery { eventRepository.pendingEvents() diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/EventProcessorTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/EventProcessorTest.kt index b0a47b97a1c..a35491fafa7 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/EventProcessorTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/EventProcessorTest.kt @@ -40,6 +40,7 @@ import io.mockative.eq import io.mockative.mock import io.mockative.once import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job import kotlinx.coroutines.cancel import kotlinx.coroutines.isActive @@ -52,6 +53,7 @@ import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertFalse +@OptIn(ExperimentalCoroutinesApi::class) class EventProcessorTest { @Test diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/base/authenticated/notification/NotificationApi.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/base/authenticated/notification/NotificationApi.kt index 51bd9c57bff..999f8abf99f 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/base/authenticated/notification/NotificationApi.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/base/authenticated/notification/NotificationApi.kt @@ -60,6 +60,7 @@ interface NotificationApi { */ suspend fun getAllNotifications(querySize: Int, queryClient: String): NetworkResponse + suspend fun getServerTime(querySize: Int): NetworkResponse suspend fun listenToLiveEvents(clientId: String): NetworkResponse>> } diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/NotificationApiV0.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/NotificationApiV0.kt index 1230c81fbb0..e130b55527a 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/NotificationApiV0.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/NotificationApiV0.kt @@ -89,9 +89,12 @@ internal open class NotificationApiV0 internal constructor( override suspend fun getAllNotifications(querySize: Int, queryClient: String): NetworkResponse = notificationsCall(querySize = querySize, queryClient = queryClient, querySince = null) + override suspend fun getServerTime(querySize: Int): NetworkResponse = + notificationsCall(querySize = querySize, queryClient = null, querySince = null).mapSuccess { it.time } + protected open suspend fun notificationsCall( querySize: Int, - queryClient: String, + queryClient: String?, querySince: String? ): NetworkResponse { return wrapKaliumResponse({ @@ -103,7 +106,7 @@ internal open class NotificationApiV0 internal constructor( }) { httpClient.get(PATH_NOTIFICATIONS) { parameter(SIZE_QUERY_KEY, querySize) - parameter(CLIENT_QUERY_KEY, queryClient) + queryClient?.let { parameter(CLIENT_QUERY_KEY, it) } querySince?.let { parameter(SINCE_QUERY_KEY, it) } } } diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/authenticated/NotificationApiV3.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/authenticated/NotificationApiV3.kt index 529d1520eb6..a4bf26d714e 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/authenticated/NotificationApiV3.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/authenticated/NotificationApiV3.kt @@ -38,13 +38,13 @@ internal open class NotificationApiV3 internal constructor( override suspend fun notificationsCall( querySize: Int, - queryClient: String, + queryClient: String?, querySince: String? ): NetworkResponse = wrapKaliumResponse { // Pretty much the same V0 request, but without the 404 overwrite httpClient.get(V0.PATH_NOTIFICATIONS) { parameter(V0.SIZE_QUERY_KEY, querySize) - parameter(V0.CLIENT_QUERY_KEY, queryClient) + queryClient?.let { parameter(V0.CLIENT_QUERY_KEY, it) } querySince?.let { parameter(V0.SINCE_QUERY_KEY, it) } } }