From a62fab6775e218b2b84bf3b6dcf593cb73e18f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Saleniuk?= <30429749+saleniuk@users.noreply.github.com> Date: Wed, 16 Aug 2023 15:21:45 +0200 Subject: [PATCH] chore: move NetworkStateObserver to network module [WPB-3475] (#1981) * chore: move NetworkStateObserver to network module * change name of duplicated logger * change pipeline from "send" to "request" * fix: detekt issues * fix: api tests * fix: api tests * fix: duplicated logger name * chore: add handling NoNetworkConnection in GetMessageAssetUseCase --- build.gradle.kts | 1 + logic/build.gradle.kts | 1 + .../kotlin/com/wire/kalium/logic/CoreLogic.kt | 2 +- .../kalium/logic/feature/UserSessionScope.kt | 2 +- .../feature/UserSessionScopeProviderImpl.kt | 2 +- .../logic/network/NetworkStateObserverImpl.kt | 2 + .../kotlin/com/wire/kalium/logic/CoreLogic.kt | 2 +- .../kalium/logic/feature/UserSessionScope.kt | 2 +- .../feature/UserSessionScopeProviderImpl.kt | 2 +- .../logic/network/NetworkStateObserverImpl.kt | 2 + .../com/wire/kalium/logic/CoreFailure.kt | 14 ++-- .../com/wire/kalium/logic/CoreLogger.kt | 4 +- .../kotlin/com/wire/kalium/logic/CoreLogic.kt | 7 +- .../wire/kalium/logic/GlobalKaliumScope.kt | 10 ++- .../kalium/logic/feature/UserSessionScope.kt | 6 +- .../ObserveIfAppUpdateRequiredUseCase.kt | 6 +- .../feature/asset/GetMessageAssetUseCase.kt | 1 + .../logic/feature/auth/AuthenticationScope.kt | 11 ++- .../logic/network/NetworkStateObserverImpl.kt | 22 ++++++ .../incremental/IncrementalSyncManager.kt | 2 +- .../kalium/logic/sync/slow/SlowSyncManager.kt | 2 +- .../incremental/IncrementalSyncManagerTest.kt | 4 +- .../logic/sync/slow/SlowSyncManagerTest.kt | 4 +- .../kotlin/com/wire/kalium/logic/CoreLogic.kt | 2 +- .../kalium/logic/feature/UserSessionScope.kt | 2 +- .../feature/UserSessionScopeProviderImpl.kt | 2 +- .../logic/network/NetworkStateObserverImpl.kt | 2 + network-util/build.gradle.kts | 43 +++++++++++ network-util/consumer-proguard-rules.pro | 13 ++++ .../kalium}/network/NetworkStateObserver.kt | 7 +- .../wire/kalium/network/NetworkUtilLogger.kt | 39 ++++++++++ network/build.gradle.kts | 1 + .../kalium/network/KaliumWebSocketFactory.kt | 2 +- .../com/wire/kalium/network/NetworkClient.kt | 20 ++++- .../AuthenticatedNetworkContainerV0.kt | 3 + .../UnauthenticatedNetworkContainerV0.kt | 3 + .../AuthenticatedNetworkContainerV2.kt | 3 + .../UnauthenticatedNetworkContainerV2.kt | 3 + .../AuthenticatedNetworkContainerV3.kt | 3 + .../UnauthenticatedNetworkContainerV3.kt | 3 + .../AuthenticatedNetworkContainerV4.kt | 3 + .../UnauthenticatedNetworkContainerV4.kt | 3 + .../network/exceptions/KaliumException.kt | 3 + .../AuthenticatedNetworkContainer.kt | 15 +++- .../UnauthenticatedNetworkContainer.kt | 10 ++- .../UnboundNetworkContainer.kt | 12 ++- .../utils/KaliumKtorNoNetworkHandler.kt | 59 +++++++++++++++ .../kotlin/com/wire/kalium/api/ApiTest.kt | 75 +++++++++++++------ .../kalium/api/TestNetworkStateObserver.kt | 36 +++++++++ .../kalium/api/common/SessionManagerTest.kt | 5 +- .../api/v0/user/logout/LogoutApiV0Test.kt | 4 +- .../kalium/api/v0/user/self/SelfApiV0Test.kt | 14 ++-- 52 files changed, 418 insertions(+), 83 deletions(-) create mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt create mode 100644 network-util/build.gradle.kts create mode 100644 network-util/consumer-proguard-rules.pro rename {logic/src/commonMain/kotlin/com/wire/kalium/logic => network-util/src/commonMain/kotlin/com/wire/kalium}/network/NetworkStateObserver.kt (89%) create mode 100644 network-util/src/commonMain/kotlin/com/wire/kalium/network/NetworkUtilLogger.kt create mode 100644 network/src/commonMain/kotlin/com/wire/kalium/network/utils/KaliumKtorNoNetworkHandler.kt create mode 100644 network/src/commonTest/kotlin/com/wire/kalium/api/TestNetworkStateObserver.kt diff --git a/build.gradle.kts b/build.gradle.kts index f2e36a2d4bc..16ac6d821b2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -136,6 +136,7 @@ dependencies { kover(project(":cryptography")) kover(project(":util")) kover(project(":network")) + kover(project(":network-util")) kover(project(":persistence")) kover(project(":logger")) kover(project(":calling")) diff --git a/logic/build.gradle.kts b/logic/build.gradle.kts index 3bcacbddb98..0baf7e3eb30 100644 --- a/logic/build.gradle.kts +++ b/logic/build.gradle.kts @@ -36,6 +36,7 @@ kotlin { val commonMain by getting { dependencies { implementation(project(":network")) + api(project(":network-util")) implementation(project(":cryptography")) implementation(project(":persistence")) implementation(project(":protobuf")) diff --git a/logic/src/androidMain/kotlin/com/wire/kalium/logic/CoreLogic.kt b/logic/src/androidMain/kotlin/com/wire/kalium/logic/CoreLogic.kt index d0648c447aa..aadf0d81116 100644 --- a/logic/src/androidMain/kotlin/com/wire/kalium/logic/CoreLogic.kt +++ b/logic/src/androidMain/kotlin/com/wire/kalium/logic/CoreLogic.kt @@ -25,7 +25,7 @@ import com.wire.kalium.logic.feature.UserSessionScopeProvider import com.wire.kalium.logic.feature.UserSessionScopeProviderImpl import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.network.NetworkStateObserverImpl import com.wire.kalium.logic.sync.GlobalWorkScheduler import com.wire.kalium.logic.sync.GlobalWorkSchedulerImpl diff --git a/logic/src/androidMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/androidMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 1b0d525dc94..886aeb6ed2f 100644 --- a/logic/src/androidMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/androidMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -30,7 +30,7 @@ import com.wire.kalium.logic.di.UserStorageProvider import com.wire.kalium.logic.feature.auth.AuthenticationScopeProvider import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.sync.UserSessionWorkScheduler import com.wire.kalium.logic.util.SecurityHelperImpl import com.wire.kalium.persistence.kmmSettings.GlobalPrefProvider diff --git a/logic/src/androidMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt b/logic/src/androidMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt index 18eae66bc0a..f7b8fdff6e8 100644 --- a/logic/src/androidMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt +++ b/logic/src/androidMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt @@ -31,7 +31,7 @@ import com.wire.kalium.logic.di.UserStorageProvider import com.wire.kalium.logic.feature.auth.AuthenticationScopeProvider import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.sync.UserSessionWorkSchedulerImpl import com.wire.kalium.persistence.kmmSettings.GlobalPrefProvider import com.wire.kalium.persistence.util.FileNameUtil diff --git a/logic/src/androidMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt b/logic/src/androidMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt index 37dfc82a37e..d767a729b2b 100644 --- a/logic/src/androidMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt +++ b/logic/src/androidMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt @@ -23,6 +23,8 @@ import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities import com.wire.kalium.logic.kaliumLogger +import com.wire.kalium.network.NetworkState +import com.wire.kalium.network.NetworkStateObserver import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/logic/src/appleMain/kotlin/com/wire/kalium/logic/CoreLogic.kt b/logic/src/appleMain/kotlin/com/wire/kalium/logic/CoreLogic.kt index e9807d30e7e..fa57144ad31 100644 --- a/logic/src/appleMain/kotlin/com/wire/kalium/logic/CoreLogic.kt +++ b/logic/src/appleMain/kotlin/com/wire/kalium/logic/CoreLogic.kt @@ -24,7 +24,7 @@ import com.wire.kalium.logic.feature.UserSessionScopeProvider import com.wire.kalium.logic.feature.UserSessionScopeProviderImpl import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.network.NetworkStateObserverImpl import com.wire.kalium.logic.sync.GlobalWorkScheduler import com.wire.kalium.logic.sync.GlobalWorkSchedulerImpl diff --git a/logic/src/appleMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/appleMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 08de8a070e4..1f75e0c897f 100644 --- a/logic/src/appleMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/appleMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -29,7 +29,7 @@ import com.wire.kalium.logic.di.UserStorageProvider import com.wire.kalium.logic.feature.auth.AuthenticationScopeProvider import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.sync.UserSessionWorkScheduler import com.wire.kalium.persistence.kmmSettings.GlobalPrefProvider diff --git a/logic/src/appleMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt b/logic/src/appleMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt index bc2332ffb58..db3c0c06068 100644 --- a/logic/src/appleMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt +++ b/logic/src/appleMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt @@ -30,7 +30,7 @@ import com.wire.kalium.logic.di.UserStorageProvider import com.wire.kalium.logic.feature.auth.AuthenticationScopeProvider import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.sync.UserSessionWorkSchedulerImpl import com.wire.kalium.persistence.kmmSettings.GlobalPrefProvider diff --git a/logic/src/appleMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt b/logic/src/appleMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt index aa2b495bba6..05c8d7faf0b 100644 --- a/logic/src/appleMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt +++ b/logic/src/appleMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt @@ -17,6 +17,8 @@ */ package com.wire.kalium.logic.network +import com.wire.kalium.network.NetworkState +import com.wire.kalium.network.NetworkStateObserver import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreFailure.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreFailure.kt index d312b962e67..c9e6204c16e 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreFailure.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreFailure.kt @@ -203,12 +203,16 @@ internal inline fun wrapApiRequest(networkCall: () -> NetworkResponse< Either.Left(NetworkFailure.ProxyError(exception.cause)) } + exception is KaliumException.NoNetwork -> { + Either.Left(NetworkFailure.NoNetworkConnection(exception)) + } + + exception is KaliumException.GenericError && exception.cause is IOException -> { + Either.Left(NetworkFailure.NoNetworkConnection(exception)) + } + else -> { - if (exception is KaliumException.GenericError && exception.cause is IOException) { - Either.Left(NetworkFailure.NoNetworkConnection(exception)) - } else { - Either.Left(NetworkFailure.ServerMiscommunication(result.kException)) - } + Either.Left(NetworkFailure.ServerMiscommunication(result.kException)) } } } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreLogger.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreLogger.kt index ad0c5ed83ba..2895e89a7cd 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreLogger.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreLogger.kt @@ -22,7 +22,7 @@ import co.touchlab.kermit.LogWriter import com.wire.kalium.cryptography.CryptographyLogger import com.wire.kalium.logger.KaliumLogLevel import com.wire.kalium.logger.KaliumLogger -import com.wire.kalium.network.NetworkLogger +import com.wire.kalium.network.NetworkUtilLogger import com.wire.kalium.persistence.PersistenceLogger internal var kaliumLogger = KaliumLogger.disabled() @@ -46,7 +46,7 @@ object CoreLogger { logWriters = logWriters ) - NetworkLogger.setLoggingLevel(level = level, logWriters = logWriters) + NetworkUtilLogger.setLoggingLevel(level = level, logWriters = logWriters) CryptographyLogger.setLoggingLevel(level = level, logWriters = logWriters) PersistenceLogger.setLoggingLevel(level = level, logWriters = logWriters) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreLogic.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreLogic.kt index ebdf38ddec8..c309edc057f 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreLogic.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/CoreLogic.kt @@ -34,7 +34,7 @@ import com.wire.kalium.logic.feature.auth.AuthenticationScopeProvider import com.wire.kalium.logic.feature.auth.autoVersioningAuth.AutoVersionAuthScopeUseCase import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.sync.GlobalWorkScheduler import com.wire.kalium.logic.sync.periodic.UpdateApiVersionsScheduler import com.wire.kalium.persistence.db.GlobalDatabaseProvider @@ -64,7 +64,8 @@ abstract class CoreLogicCommon internal constructor( globalPreferences, kaliumConfigs, userSessionScopeProvider, - authenticationScopeProvider + authenticationScopeProvider, + networkStateObserver ) @Suppress("MemberVisibilityCanBePrivate") // Can be used by other targets like iOS and JS @@ -72,7 +73,7 @@ abstract class CoreLogicCommon internal constructor( serverConfig: ServerConfig, proxyCredentials: ProxyCredentials? = null ): AuthenticationScope = - authenticationScopeProvider.provide(serverConfig, proxyCredentials, getGlobalScope().serverConfigRepository) + authenticationScopeProvider.provide(serverConfig, proxyCredentials, getGlobalScope().serverConfigRepository, networkStateObserver) @Suppress("MemberVisibilityCanBePrivate") // Can be used by other targets like iOS and JS abstract fun getSessionScope(userId: UserId): UserSessionScope diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/GlobalKaliumScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/GlobalKaliumScope.kt index 13b774f0f7a..40e001b2cef 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/GlobalKaliumScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/GlobalKaliumScope.kt @@ -64,6 +64,7 @@ import com.wire.kalium.logic.feature.user.ObserveValidAccountsUseCaseImpl import com.wire.kalium.logic.feature.user.webSocketStatus.ObservePersistentWebSocketConnectionStatusUseCase import com.wire.kalium.logic.feature.user.webSocketStatus.ObservePersistentWebSocketConnectionStatusUseCaseImpl import com.wire.kalium.logic.featureFlags.KaliumConfigs +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.networkContainer.UnboundNetworkContainer import com.wire.kalium.network.networkContainer.UnboundNetworkContainerCommon import com.wire.kalium.persistence.db.GlobalDatabaseProvider @@ -81,20 +82,22 @@ import kotlin.coroutines.CoroutineContext * @see [com.wire.kalium.logic.feature.auth.AuthenticationScope] * @see [com.wire.kalium.logic.feature.UserSessionScope] */ - +@Suppress("LongParameterList") class GlobalKaliumScope internal constructor( userAgent: String, private val globalDatabase: GlobalDatabaseProvider, private val globalPreferences: GlobalPrefProvider, private val kaliumConfigs: KaliumConfigs, private val userSessionScopeProvider: Lazy, - private val authenticationScopeProvider: AuthenticationScopeProvider + private val authenticationScopeProvider: AuthenticationScopeProvider, + private val networkStateObserver: NetworkStateObserver ) : CoroutineScope { override val coroutineContext: CoroutineContext = SupervisorJob() val unboundNetworkContainer: UnboundNetworkContainer by lazy { UnboundNetworkContainerCommon( + networkStateObserver, kaliumConfigs.developmentApiEnabled, userAgent, kaliumConfigs.ignoreSSLCertificatesForUnboundCalls @@ -161,7 +164,8 @@ class GlobalKaliumScope internal constructor( get() = ObserveIfAppUpdateRequiredUseCaseImpl( serverConfigRepository, authenticationScopeProvider, - userSessionScopeProvider.value + userSessionScopeProvider.value, + networkStateObserver ) val checkSystemIntegrity: CheckSystemIntegrityUseCase 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 44ba1627b98..4528961bf27 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 @@ -257,7 +257,7 @@ import com.wire.kalium.logic.functional.map import com.wire.kalium.logic.functional.onSuccess import com.wire.kalium.logic.network.ApiMigrationManager import com.wire.kalium.logic.network.ApiMigrationV3 -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.network.SessionManagerImpl import com.wire.kalium.logic.sync.MissingMetadataUpdateManager import com.wire.kalium.logic.sync.MissingMetadataUpdateManagerImpl @@ -440,6 +440,7 @@ class UserSessionScope internal constructor( logout = { logoutReason -> logout(logoutReason) } ) private val authenticatedNetworkContainer: AuthenticatedNetworkContainer = AuthenticatedNetworkContainer.create( + networkStateObserver, sessionManager, UserIdDTO(userId.value, userId.domain), userAgent @@ -451,7 +452,8 @@ class UserSessionScope internal constructor( val authenticationScope: AuthenticationScope = authenticationScopeProvider.provide( sessionManager.getServerConfig(), sessionManager.getProxyCredentials(), - globalScope.serverConfigRepository + globalScope.serverConfigRepository, + networkStateObserver ) private val userConfigRepository: UserConfigRepository diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/appVersioning/ObserveIfAppUpdateRequiredUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/appVersioning/ObserveIfAppUpdateRequiredUseCase.kt index d78d1e069a7..89f965999d7 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/appVersioning/ObserveIfAppUpdateRequiredUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/appVersioning/ObserveIfAppUpdateRequiredUseCase.kt @@ -28,6 +28,7 @@ import com.wire.kalium.logic.functional.getOrElse import com.wire.kalium.logic.functional.intervalFlow import com.wire.kalium.logic.functional.onFailure import com.wire.kalium.logic.kaliumLogger +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.util.DateTimeUtil import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.async @@ -54,7 +55,8 @@ interface ObserveIfAppUpdateRequiredUseCase { class ObserveIfAppUpdateRequiredUseCaseImpl internal constructor( private val serverConfigRepository: ServerConfigRepository, private val authenticationScopeProvider: AuthenticationScopeProvider, - private val userSessionScopeProvider: UserSessionScopeProvider + private val userSessionScopeProvider: UserSessionScopeProvider, + private val networkStateObserver: NetworkStateObserver ) : ObserveIfAppUpdateRequiredUseCase { @OptIn(ExperimentalCoroutinesApi::class) @@ -96,7 +98,7 @@ class ObserveIfAppUpdateRequiredUseCaseImpl internal constructor( withContext(coroutineContext) { async { val isUpdateRequired = authenticationScopeProvider - .provide(serverConfig, proxyCredentials, serverConfigRepository) + .provide(serverConfig, proxyCredentials, serverConfigRepository, networkStateObserver) .checkIfUpdateRequired(currentAppVersion, serverConfig.links.blackList) serverConfig.id to isUpdateRequired } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCase.kt index 2fa9407ce3d..1cb7f4ad33a 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/GetMessageAssetUseCase.kt @@ -126,6 +126,7 @@ internal class GetMessageAssetUseCaseImpl( } it is NetworkFailure.FederatedBackendFailure -> MessageAssetResult.Failure(it, false) + it is NetworkFailure.NoNetworkConnection -> MessageAssetResult.Failure(it, true) else -> MessageAssetResult.Failure(it, true) } }, { decodedAssetPath -> diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/AuthenticationScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/AuthenticationScope.kt index 130431e5915..aacbc4a687f 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/AuthenticationScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/auth/AuthenticationScope.kt @@ -37,6 +37,7 @@ import com.wire.kalium.logic.feature.appVersioning.CheckIfUpdateRequiredUseCaseI import com.wire.kalium.logic.feature.auth.sso.SSOLoginScope import com.wire.kalium.logic.feature.auth.verification.RequestSecondFactorVerificationCodeUseCase import com.wire.kalium.logic.feature.register.RegisterScope +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.networkContainer.UnauthenticatedNetworkContainer import io.ktor.util.collections.ConcurrentMap @@ -52,14 +53,16 @@ class AuthenticationScopeProvider internal constructor( internal fun provide( serverConfig: ServerConfig, proxyCredentials: ProxyCredentials?, - serverConfigRepository: ServerConfigRepository + serverConfigRepository: ServerConfigRepository, + networkStateObserver: NetworkStateObserver, ): AuthenticationScope = authenticationScopeStorage.computeIfAbsent(serverConfig to proxyCredentials) { AuthenticationScope( userAgent, serverConfig, proxyCredentials, - serverConfigRepository + serverConfigRepository, + networkStateObserver ) } } @@ -68,10 +71,12 @@ class AuthenticationScope internal constructor( private val userAgent: String, private val serverConfig: ServerConfig, private val proxyCredentials: ProxyCredentials?, - private val serverConfigRepository: ServerConfigRepository + private val serverConfigRepository: ServerConfigRepository, + private val networkStateObserver: NetworkStateObserver ) { private val unauthenticatedNetworkContainer: UnauthenticatedNetworkContainer by lazy { UnauthenticatedNetworkContainer.create( + networkStateObserver, MapperProvider.serverConfigMapper().toDTO(serverConfig), proxyCredentials?.let { MapperProvider.sessionMapper().fromModelToProxyCredentialsDTO(it) }, userAgent diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt new file mode 100644 index 00000000000..9ed93fc62ac --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt @@ -0,0 +1,22 @@ +/* + * Wire + * Copyright (C) 2023 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.network + +import com.wire.kalium.network.NetworkStateObserver + +internal expect class NetworkStateObserverImpl : NetworkStateObserver diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/incremental/IncrementalSyncManager.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/incremental/IncrementalSyncManager.kt index 9cecf7120e2..c919c9938d6 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/incremental/IncrementalSyncManager.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/incremental/IncrementalSyncManager.kt @@ -25,11 +25,11 @@ import com.wire.kalium.logic.data.sync.IncrementalSyncStatus import com.wire.kalium.logic.data.sync.SlowSyncRepository import com.wire.kalium.logic.data.sync.SlowSyncStatus import com.wire.kalium.logic.kaliumLogger -import com.wire.kalium.logic.network.NetworkStateObserver import com.wire.kalium.logic.sync.SyncExceptionHandler import com.wire.kalium.logic.sync.slow.SlowSyncManager import com.wire.kalium.logic.util.ExponentialDurationHelper import com.wire.kalium.logic.util.ExponentialDurationHelperImpl +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.util.KaliumDispatcher import com.wire.kalium.util.KaliumDispatcherImpl import kotlinx.coroutines.CoroutineScope diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt index 08792fe0dea..fd36bca5610 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManager.kt @@ -24,7 +24,7 @@ import com.wire.kalium.logic.data.sync.SlowSyncRepository import com.wire.kalium.logic.data.sync.SlowSyncStatus import com.wire.kalium.logic.functional.combine import com.wire.kalium.logic.kaliumLogger -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.sync.SyncExceptionHandler import com.wire.kalium.logic.sync.incremental.IncrementalSyncManager import com.wire.kalium.logic.util.ExponentialDurationHelper diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/IncrementalSyncManagerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/IncrementalSyncManagerTest.kt index e49a761747c..a7baff92ab5 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/IncrementalSyncManagerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/incremental/IncrementalSyncManagerTest.kt @@ -24,8 +24,8 @@ import com.wire.kalium.logic.data.sync.IncrementalSyncStatus import com.wire.kalium.logic.data.sync.SlowSyncRepository import com.wire.kalium.logic.data.sync.SlowSyncRepositoryImpl import com.wire.kalium.logic.data.sync.SlowSyncStatus -import com.wire.kalium.logic.network.NetworkState -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkState +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.test_util.TestKaliumDispatcher import com.wire.kalium.logic.util.ExponentialDurationHelper import com.wire.kalium.logic.util.flowThatFailsOnFirstTime diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManagerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManagerTest.kt index ba80de5ca23..efa95f3a1f0 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManagerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/sync/slow/SlowSyncManagerTest.kt @@ -21,8 +21,8 @@ package com.wire.kalium.logic.sync.slow import com.wire.kalium.logic.data.sync.SlowSyncRepository import com.wire.kalium.logic.data.sync.SlowSyncStatus import com.wire.kalium.logic.data.sync.SlowSyncStep -import com.wire.kalium.logic.network.NetworkState -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkState +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.test_util.TestKaliumDispatcher import com.wire.kalium.logic.util.ExponentialDurationHelper import com.wire.kalium.logic.util.flowThatFailsOnFirstTime diff --git a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/CoreLogic.kt b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/CoreLogic.kt index b00ac1a3849..564e95956d8 100644 --- a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/CoreLogic.kt +++ b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/CoreLogic.kt @@ -24,7 +24,7 @@ import com.wire.kalium.logic.feature.UserSessionScopeProvider import com.wire.kalium.logic.feature.UserSessionScopeProviderImpl import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.network.NetworkStateObserverImpl import com.wire.kalium.logic.sync.GlobalWorkScheduler import com.wire.kalium.logic.sync.GlobalWorkSchedulerImpl diff --git a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 08de8a070e4..1f75e0c897f 100644 --- a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -29,7 +29,7 @@ import com.wire.kalium.logic.di.UserStorageProvider import com.wire.kalium.logic.feature.auth.AuthenticationScopeProvider import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.sync.UserSessionWorkScheduler import com.wire.kalium.persistence.kmmSettings.GlobalPrefProvider diff --git a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt index 4bb36277a08..21038c3f36b 100644 --- a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt +++ b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/feature/UserSessionScopeProviderImpl.kt @@ -30,7 +30,7 @@ import com.wire.kalium.logic.di.UserStorageProvider import com.wire.kalium.logic.feature.auth.AuthenticationScopeProvider import com.wire.kalium.logic.feature.call.GlobalCallManager import com.wire.kalium.logic.featureFlags.KaliumConfigs -import com.wire.kalium.logic.network.NetworkStateObserver +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.logic.sync.UserSessionWorkSchedulerImpl import com.wire.kalium.persistence.kmmSettings.GlobalPrefProvider diff --git a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt index aa2b495bba6..05c8d7faf0b 100644 --- a/logic/src/jvmMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt +++ b/logic/src/jvmMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserverImpl.kt @@ -17,6 +17,8 @@ */ package com.wire.kalium.logic.network +import com.wire.kalium.network.NetworkState +import com.wire.kalium.network.NetworkStateObserver import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/network-util/build.gradle.kts b/network-util/build.gradle.kts new file mode 100644 index 00000000000..a6fa3a345dc --- /dev/null +++ b/network-util/build.gradle.kts @@ -0,0 +1,43 @@ +/* + * Wire + * Copyright (C) 2023 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/. + */ + +@Suppress("DSL_SCOPE_VIOLATION") +plugins { + id(libs.plugins.android.library.get().pluginId) + id(libs.plugins.kotlin.multiplatform.get().pluginId) + alias(libs.plugins.kotlin.serialization) + id(libs.plugins.kalium.library.get().pluginId) +} + +kaliumLibrary { + multiplatform { + enableJs.set(false) + } +} + +kotlin { + sourceSets { + val commonMain by getting { + dependencies { + api(project(":logger")) + + implementation(libs.coroutines.core) + } + } + } +} diff --git a/network-util/consumer-proguard-rules.pro b/network-util/consumer-proguard-rules.pro new file mode 100644 index 00000000000..3c7532c6de7 --- /dev/null +++ b/network-util/consumer-proguard-rules.pro @@ -0,0 +1,13 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserver.kt b/network-util/src/commonMain/kotlin/com/wire/kalium/network/NetworkStateObserver.kt similarity index 89% rename from logic/src/commonMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserver.kt rename to network-util/src/commonMain/kotlin/com/wire/kalium/network/NetworkStateObserver.kt index 32024c7f2b8..93a7369f00e 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/network/NetworkStateObserver.kt +++ b/network-util/src/commonMain/kotlin/com/wire/kalium/network/NetworkStateObserver.kt @@ -15,9 +15,8 @@ * 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.network +package com.wire.kalium.network -import com.wire.kalium.logic.kaliumLogger import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filter @@ -32,7 +31,7 @@ interface NetworkStateObserver { // Delay which will be completed earlier if there is a reconnection in the meantime. suspend fun delayUntilConnectedWithInternetAgain(delay: Duration) { // Delay for given amount but break it if reconnected again. - kaliumLogger.i("$TAG delayUntilConnectedWithInternetAgain") + kaliumUtilLogger.i("$TAG delayUntilConnectedWithInternetAgain") withTimeoutOrNull(delay) { // Drop the current value, so it will complete only if the connection changed again to connected during that time. observeNetworkState() @@ -47,8 +46,6 @@ interface NetworkStateObserver { } } -internal expect class NetworkStateObserverImpl : NetworkStateObserver - sealed class NetworkState { object ConnectedWithInternet : NetworkState() object ConnectedWithoutInternet : NetworkState() diff --git a/network-util/src/commonMain/kotlin/com/wire/kalium/network/NetworkUtilLogger.kt b/network-util/src/commonMain/kotlin/com/wire/kalium/network/NetworkUtilLogger.kt new file mode 100644 index 00000000000..120ae5f77ed --- /dev/null +++ b/network-util/src/commonMain/kotlin/com/wire/kalium/network/NetworkUtilLogger.kt @@ -0,0 +1,39 @@ +/* + * Wire + * Copyright (C) 2023 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.network + +import co.touchlab.kermit.LogWriter +import com.wire.kalium.logger.KaliumLogLevel +import com.wire.kalium.logger.KaliumLogger + +internal var kaliumUtilLogger = KaliumLogger.disabled() + +object NetworkUtilLogger { + fun setLoggingLevel(level: KaliumLogLevel, vararg logWriters: LogWriter = arrayOf()) { + kaliumUtilLogger = KaliumLogger( + config = KaliumLogger.Config( + severity = level, + tag = "Network" + ), + logWriters = logWriters + ) + } + + val isRequestLoggingEnabled: Boolean get() = kaliumUtilLogger.severity in setOf(KaliumLogLevel.VERBOSE, KaliumLogLevel.DEBUG) +} diff --git a/network/build.gradle.kts b/network/build.gradle.kts index 3a2165aa99d..ba99d43f0b6 100644 --- a/network/build.gradle.kts +++ b/network/build.gradle.kts @@ -36,6 +36,7 @@ kotlin { dependencies { implementation(project(":protobuf")) implementation(project(":util")) + implementation(project(":network-util")) api(project(":logger")) // coroutines diff --git a/network/src/commonJvmAndroid/kotlin/com/wire/kalium/network/KaliumWebSocketFactory.kt b/network/src/commonJvmAndroid/kotlin/com/wire/kalium/network/KaliumWebSocketFactory.kt index 22fce28340a..dc63a2dc3d3 100644 --- a/network/src/commonJvmAndroid/kotlin/com/wire/kalium/network/KaliumWebSocketFactory.kt +++ b/network/src/commonJvmAndroid/kotlin/com/wire/kalium/network/KaliumWebSocketFactory.kt @@ -39,7 +39,7 @@ class KaliumWebSocketFactory(private val okHttpClient: OkHttpClient) : WebSocket /** * Wraps the provided [wrappedListener], keeping the normal behaviour, - * but using [kaliumLogger] to log all operations. + * but using [kaliumUtilLogger] to log all operations. */ inner class WrapperListener(private val wrappedListener: WebSocketListener) : WebSocketListener() { override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/NetworkClient.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/NetworkClient.kt index e6ffe908430..0dfbbcf2b1a 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/NetworkClient.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/NetworkClient.kt @@ -25,6 +25,7 @@ import com.wire.kalium.network.session.SessionManager import com.wire.kalium.network.session.installAuth import com.wire.kalium.network.tools.KtxSerializer import com.wire.kalium.network.tools.ServerConfigDTO +import com.wire.kalium.network.utils.KaliumKtorNoNetworkHandler import com.wire.kalium.network.utils.installWireDefaultRequest import io.ktor.client.HttpClient import io.ktor.client.HttpClientConfig @@ -45,12 +46,14 @@ import io.ktor.serialization.kotlinx.json.json * necessary Authentication headers, and refresh tokens as they expire. */ internal class AuthenticatedNetworkClient( + networkStateObserver: NetworkStateObserver, engine: HttpClientEngine, serverConfigDTO: ServerConfigDTO, bearerAuthProvider: BearerAuthProvider, installCompression: Boolean = true ) { val httpClient: HttpClient = provideBaseHttpClient( + networkStateObserver, engine, installCompression ) { @@ -69,10 +72,11 @@ internal class AuthenticatedNetworkClient( * Serialization, and Content Negotiation. */ internal class UnauthenticatedNetworkClient( + networkStateObserver: NetworkStateObserver, engine: HttpClientEngine, backendLinks: ServerConfigDTO ) { - val httpClient: HttpClient = provideBaseHttpClient(engine) { + val httpClient: HttpClient = provideBaseHttpClient(networkStateObserver, engine) { installWireDefaultRequest(backendLinks) } } @@ -84,9 +88,10 @@ internal class UnauthenticatedNetworkClient( * Unlike others, this one has no strict ties with any API version nor default Base Url */ internal class UnboundNetworkClient( + networkStateObserver: NetworkStateObserver, engine: HttpClientEngine ) { - val httpClient: HttpClient = provideBaseHttpClient(engine) + val httpClient: HttpClient = provideBaseHttpClient(networkStateObserver, engine) } /** @@ -95,6 +100,7 @@ internal class UnboundNetworkClient( * necessary Authentication headers, and refresh tokens as they expire. */ internal class AuthenticatedWebSocketClient( + private val networkStateObserver: NetworkStateObserver, private val engine: HttpClientEngine, private val bearerAuthProvider: BearerAuthProvider, private val serverConfigDTO: ServerConfigDTO, @@ -106,7 +112,7 @@ internal class AuthenticatedWebSocketClient( * as the old one can be dead. */ fun createDisposableHttpClient(): HttpClient = - provideBaseHttpClient(engine) { + provideBaseHttpClient(networkStateObserver, engine) { installWireDefaultRequest(serverConfigDTO) installAuth(bearerAuthProvider) install(ContentNegotiation) { @@ -122,6 +128,7 @@ internal class AuthenticatedWebSocketClient( } internal fun provideBaseHttpClient( + networkStateObserver: NetworkStateObserver, engine: HttpClientEngine, installCompression: Boolean = true, config: HttpClientConfig<*>.() -> Unit = {} @@ -130,7 +137,7 @@ internal fun provideBaseHttpClient( agent = KaliumUserAgentProvider.userAgent } - if (NetworkLogger.isRequestLoggingEnabled) { + if (NetworkUtilLogger.isRequestLoggingEnabled) { install(KaliumKtorCustomLogging) { level = LogLevel.ALL } @@ -146,6 +153,11 @@ internal fun provideBaseHttpClient( install(ContentNegotiation) { json(KtxSerializer.json) } + + install(KaliumKtorNoNetworkHandler) { + this.networkStateObserver = networkStateObserver + } + expectSuccess = false config() } diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/networkContainer/AuthenticatedNetworkContainerV0.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/networkContainer/AuthenticatedNetworkContainerV0.kt index c677a6f23a0..4187b93fd65 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/networkContainer/AuthenticatedNetworkContainerV0.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/authenticated/networkContainer/AuthenticatedNetworkContainerV0.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.api.v0.authenticated.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.api.base.authenticated.AccessTokenApi import com.wire.kalium.network.api.base.authenticated.CallApi import com.wire.kalium.network.api.base.authenticated.TeamsApi @@ -67,11 +68,13 @@ import com.wire.kalium.network.session.SessionManager import io.ktor.client.engine.HttpClientEngine internal class AuthenticatedNetworkContainerV0 internal constructor( + private val networkStateObserver: NetworkStateObserver, private val sessionManager: SessionManager, engine: HttpClientEngine = defaultHttpEngine(sessionManager.serverConfig().links.apiProxy, sessionManager.proxyCredentials()) ) : AuthenticatedNetworkContainer, AuthenticatedHttpClientProvider by AuthenticatedHttpClientProviderImpl( sessionManager, + networkStateObserver, { httpClient -> AccessTokenApiV0(httpClient) }, engine ) { diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV0.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV0.kt index 69f112992b2..683f721ed82 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV0.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v0/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV0.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.api.v0.unauthenticated.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.api.base.model.ProxyCredentialsDTO import com.wire.kalium.network.api.base.unauthenticated.DomainLookupApi import com.wire.kalium.network.api.base.unauthenticated.LoginApi @@ -39,11 +40,13 @@ import com.wire.kalium.network.tools.ServerConfigDTO import io.ktor.client.engine.HttpClientEngine class UnauthenticatedNetworkContainerV0 internal constructor( + networkStateObserver: NetworkStateObserver, backendLinks: ServerConfigDTO, proxyCredentials: ProxyCredentialsDTO?, engine: HttpClientEngine = defaultHttpEngine(backendLinks.links.apiProxy, proxyCredentials) ) : UnauthenticatedNetworkContainer, UnauthenticatedNetworkClientProvider by UnauthenticatedNetworkClientProviderImpl( + networkStateObserver, backendLinks, proxyCredentials, engine diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v2/authenticated/networkContainer/AuthenticatedNetworkContainerV2.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v2/authenticated/networkContainer/AuthenticatedNetworkContainerV2.kt index f1da148b7c3..355c3e19ec1 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v2/authenticated/networkContainer/AuthenticatedNetworkContainerV2.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v2/authenticated/networkContainer/AuthenticatedNetworkContainerV2.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.api.v2.authenticated.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.api.v2.authenticated.E2EIApiV2 import com.wire.kalium.network.api.base.authenticated.AccessTokenApi import com.wire.kalium.network.api.base.authenticated.CallApi @@ -68,12 +69,14 @@ import com.wire.kalium.network.session.SessionManager import io.ktor.client.engine.HttpClientEngine internal class AuthenticatedNetworkContainerV2 internal constructor( + private val networkStateObserver: NetworkStateObserver, private val sessionManager: SessionManager, private val selfUserId: UserId, engine: HttpClientEngine = defaultHttpEngine(sessionManager.serverConfig().links.apiProxy, sessionManager.proxyCredentials()) ) : AuthenticatedNetworkContainer, AuthenticatedHttpClientProvider by AuthenticatedHttpClientProviderImpl( sessionManager, + networkStateObserver, { httpClient -> AccessTokenApiV2(httpClient) }, engine ) { diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v2/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV2.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v2/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV2.kt index fb424e6b74a..2a92b352865 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v2/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV2.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v2/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV2.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.api.v2.unauthenticated.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.api.base.model.ProxyCredentialsDTO import com.wire.kalium.network.api.base.unauthenticated.DomainLookupApi import com.wire.kalium.network.api.base.unauthenticated.LoginApi @@ -39,11 +40,13 @@ import com.wire.kalium.network.tools.ServerConfigDTO import io.ktor.client.engine.HttpClientEngine class UnauthenticatedNetworkContainerV2 internal constructor( + networkStateObserver: NetworkStateObserver, backendLinks: ServerConfigDTO, proxyCredentials: ProxyCredentialsDTO?, engine: HttpClientEngine = defaultHttpEngine(backendLinks.links.apiProxy, proxyCredentials) ) : UnauthenticatedNetworkContainer, UnauthenticatedNetworkClientProvider by UnauthenticatedNetworkClientProviderImpl( + networkStateObserver, backendLinks, proxyCredentials, engine diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/authenticated/networkContainer/AuthenticatedNetworkContainerV3.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/authenticated/networkContainer/AuthenticatedNetworkContainerV3.kt index b6909c7b9c9..fd3f28163ef 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/authenticated/networkContainer/AuthenticatedNetworkContainerV3.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/authenticated/networkContainer/AuthenticatedNetworkContainerV3.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.api.v3.authenticated.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.api.base.authenticated.AccessTokenApi import com.wire.kalium.network.api.base.authenticated.CallApi import com.wire.kalium.network.api.base.authenticated.TeamsApi @@ -69,12 +70,14 @@ import com.wire.kalium.network.session.SessionManager import io.ktor.client.engine.HttpClientEngine internal class AuthenticatedNetworkContainerV3 internal constructor( + private val networkStateObserver: NetworkStateObserver, private val sessionManager: SessionManager, private val selfUserId: UserId, engine: HttpClientEngine = defaultHttpEngine(sessionManager.serverConfig().links.apiProxy, sessionManager.proxyCredentials()) ) : AuthenticatedNetworkContainer, AuthenticatedHttpClientProvider by AuthenticatedHttpClientProviderImpl( sessionManager, + networkStateObserver, { httpClient -> AccessTokenApiV3(httpClient) }, engine ) { diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV3.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV3.kt index af52c17a818..53ea34685f6 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV3.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v3/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV3.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.api.v3.unauthenticated.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.api.base.model.ProxyCredentialsDTO import com.wire.kalium.network.api.base.unauthenticated.DomainLookupApi import com.wire.kalium.network.api.base.unauthenticated.LoginApi @@ -39,11 +40,13 @@ import com.wire.kalium.network.tools.ServerConfigDTO import io.ktor.client.engine.HttpClientEngine class UnauthenticatedNetworkContainerV3 internal constructor( + networkStateObserver: NetworkStateObserver, backendLinks: ServerConfigDTO, proxyCredentials: ProxyCredentialsDTO?, engine: HttpClientEngine = defaultHttpEngine(backendLinks.links.apiProxy, proxyCredentials), ) : UnauthenticatedNetworkContainer, UnauthenticatedNetworkClientProvider by UnauthenticatedNetworkClientProviderImpl( + networkStateObserver, backendLinks, proxyCredentials, engine diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v4/authenticated/networkContainer/AuthenticatedNetworkContainerV4.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v4/authenticated/networkContainer/AuthenticatedNetworkContainerV4.kt index d8727f32dfc..f08de67efbf 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v4/authenticated/networkContainer/AuthenticatedNetworkContainerV4.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v4/authenticated/networkContainer/AuthenticatedNetworkContainerV4.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.api.v4.authenticated.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.api.base.authenticated.AccessTokenApi import com.wire.kalium.network.api.base.authenticated.CallApi import com.wire.kalium.network.api.base.authenticated.TeamsApi @@ -68,6 +69,7 @@ import com.wire.kalium.network.session.SessionManager import io.ktor.client.engine.HttpClientEngine internal class AuthenticatedNetworkContainerV4 internal constructor( + private val networkStateObserver: NetworkStateObserver, private val sessionManager: SessionManager, private val selfUserId: UserId, engine: HttpClientEngine = defaultHttpEngine( @@ -77,6 +79,7 @@ internal class AuthenticatedNetworkContainerV4 internal constructor( ) : AuthenticatedNetworkContainer, AuthenticatedHttpClientProvider by AuthenticatedHttpClientProviderImpl( sessionManager, + networkStateObserver, { httpClient -> AccessTokenApiV4(httpClient) }, engine ) { diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v4/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV4.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v4/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV4.kt index 8d2828f7ed2..346e95d1e31 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/api/v4/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV4.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/api/v4/unauthenticated/networkContainer/UnauthenticatedNetworkContainerV4.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.api.v4.unauthenticated.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.api.base.model.ProxyCredentialsDTO import com.wire.kalium.network.api.base.unauthenticated.DomainLookupApi import com.wire.kalium.network.api.base.unauthenticated.LoginApi @@ -39,11 +40,13 @@ import com.wire.kalium.network.tools.ServerConfigDTO import io.ktor.client.engine.HttpClientEngine class UnauthenticatedNetworkContainerV4 internal constructor( + networkStateObserver: NetworkStateObserver, backendLinks: ServerConfigDTO, proxyCredentials: ProxyCredentialsDTO?, engine: HttpClientEngine = defaultHttpEngine(backendLinks.links.apiProxy, proxyCredentials), ) : UnauthenticatedNetworkContainer, UnauthenticatedNetworkClientProvider by UnauthenticatedNetworkClientProviderImpl( + networkStateObserver, backendLinks, proxyCredentials, engine diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/exceptions/KaliumException.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/exceptions/KaliumException.kt index e7dc7286589..87575b423ae 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/exceptions/KaliumException.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/exceptions/KaliumException.kt @@ -20,6 +20,7 @@ package com.wire.kalium.network.exceptions +import com.wire.kalium.network.NetworkState import com.wire.kalium.network.api.base.authenticated.message.QualifiedSendMessageResponse import com.wire.kalium.network.api.base.authenticated.message.SendMessageResponse import com.wire.kalium.network.api.base.model.ErrorResponse @@ -57,6 +58,8 @@ import io.ktor.http.HttpStatusCode sealed class KaliumException : Exception() { + data class NoNetwork(val networkState: NetworkState = NetworkState.NotConnected) : KaliumException() + data class Unauthorized(val errorCode: Int) : KaliumException() /** diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/AuthenticatedNetworkContainer.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/AuthenticatedNetworkContainer.kt index a8d1f2bea09..b400a2b01a6 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/AuthenticatedNetworkContainer.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/AuthenticatedNetworkContainer.kt @@ -20,6 +20,7 @@ package com.wire.kalium.network.networkContainer import com.wire.kalium.network.AuthenticatedNetworkClient import com.wire.kalium.network.AuthenticatedWebSocketClient +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.api.base.authenticated.AccessTokenApi import com.wire.kalium.network.api.base.authenticated.CallApi import com.wire.kalium.network.api.base.authenticated.TeamsApi @@ -105,6 +106,7 @@ interface AuthenticatedNetworkContainer { companion object { fun create( + networkStateObserver: NetworkStateObserver, sessionManager: SessionManager, selfUserId: UserId, userAgent: String @@ -114,24 +116,29 @@ interface AuthenticatedNetworkContainer { return when (val version = sessionManager.serverConfig().metaData.commonApiVersion.version) { 0 -> AuthenticatedNetworkContainerV0( - sessionManager + networkStateObserver, + sessionManager, ) 1 -> AuthenticatedNetworkContainerV0( - sessionManager + networkStateObserver, + sessionManager, ) 2 -> AuthenticatedNetworkContainerV2( + networkStateObserver, sessionManager, selfUserId ) 3 -> AuthenticatedNetworkContainerV3( + networkStateObserver, sessionManager, selfUserId ) 4 -> AuthenticatedNetworkContainerV4( + networkStateObserver, sessionManager, selfUserId ) @@ -152,6 +159,7 @@ internal interface AuthenticatedHttpClientProvider { internal class AuthenticatedHttpClientProviderImpl( private val sessionManager: SessionManager, + private val networkStateObserver: NetworkStateObserver, private val accessTokenApi: (httpClient: HttpClient) -> AccessTokenApi, private val engine: HttpClientEngine = defaultHttpEngine(sessionManager.serverConfig().links.apiProxy), ) : AuthenticatedHttpClientProvider { @@ -178,6 +186,7 @@ internal class AuthenticatedHttpClientProviderImpl( override val networkClient by lazy { AuthenticatedNetworkClient( + networkStateObserver, engine, sessionManager.serverConfig(), bearerAuthProvider @@ -185,6 +194,7 @@ internal class AuthenticatedHttpClientProviderImpl( } override val websocketClient by lazy { AuthenticatedWebSocketClient( + networkStateObserver, engine, bearerAuthProvider, sessionManager.serverConfig() @@ -192,6 +202,7 @@ internal class AuthenticatedHttpClientProviderImpl( } override val networkClientWithoutCompression by lazy { AuthenticatedNetworkClient( + networkStateObserver, engine, sessionManager.serverConfig(), bearerAuthProvider, diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/UnauthenticatedNetworkContainer.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/UnauthenticatedNetworkContainer.kt index d3fa49b0854..391bb30c8bb 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/UnauthenticatedNetworkContainer.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/UnauthenticatedNetworkContainer.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.UnauthenticatedNetworkClient import com.wire.kalium.network.api.base.model.ProxyCredentialsDTO import com.wire.kalium.network.api.base.unauthenticated.DomainLookupApi @@ -45,6 +46,7 @@ interface UnauthenticatedNetworkContainer { companion object { fun create( + networkStateObserver: NetworkStateObserver, serverConfigDTO: ServerConfigDTO, proxyCredentials: ProxyCredentialsDTO?, userAgent: String @@ -54,26 +56,31 @@ interface UnauthenticatedNetworkContainer { return when (serverConfigDTO.metaData.commonApiVersion.version) { 0 -> UnauthenticatedNetworkContainerV0( + networkStateObserver, serverConfigDTO, proxyCredentials = proxyCredentials ) 1 -> UnauthenticatedNetworkContainerV0( + networkStateObserver, serverConfigDTO, proxyCredentials = proxyCredentials ) 2 -> UnauthenticatedNetworkContainerV2( + networkStateObserver, serverConfigDTO, proxyCredentials = proxyCredentials ) 3 -> UnauthenticatedNetworkContainerV3( + networkStateObserver, serverConfigDTO, proxyCredentials = proxyCredentials ) 4 -> UnauthenticatedNetworkContainerV4( + networkStateObserver, serverConfigDTO, proxyCredentials = proxyCredentials ) @@ -89,11 +96,12 @@ internal interface UnauthenticatedNetworkClientProvider { } internal class UnauthenticatedNetworkClientProviderImpl internal constructor( + networkStateObserver: NetworkStateObserver, backendLinks: ServerConfigDTO, proxyCredentials: ProxyCredentialsDTO?, engine: HttpClientEngine = defaultHttpEngine(backendLinks.links.apiProxy, proxyCredentials), ) : UnauthenticatedNetworkClientProvider { override val unauthenticatedNetworkClient by lazy { - UnauthenticatedNetworkClient(engine, backendLinks) + UnauthenticatedNetworkClient(networkStateObserver, engine, backendLinks) } } diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/UnboundNetworkContainer.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/UnboundNetworkContainer.kt index 42cd0d0a9fc..5b39ba7e863 100644 --- a/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/UnboundNetworkContainer.kt +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/networkContainer/UnboundNetworkContainer.kt @@ -18,6 +18,7 @@ package com.wire.kalium.network.networkContainer +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.UnboundNetworkClient import com.wire.kalium.network.api.base.unbound.acme.ACMEApi import com.wire.kalium.network.api.base.unbound.acme.ACMEApiImpl @@ -39,6 +40,7 @@ private interface UnboundNetworkClientProvider { } internal class UnboundNetworkClientProviderImpl( + networkStateObserver: NetworkStateObserver, val developmentApiEnabled: Boolean, userAgent: String, private val ignoreSSLCertificates: Boolean, @@ -50,16 +52,22 @@ internal class UnboundNetworkClientProviderImpl( } override val unboundNetworkClient by lazy { - UnboundNetworkClient(engine) + UnboundNetworkClient(networkStateObserver, engine) } } class UnboundNetworkContainerCommon( + networkStateObserver: NetworkStateObserver, private val developmentApiEnabled: Boolean, userAgent: String, private val ignoreSSLCertificates: Boolean, ) : UnboundNetworkContainer, - UnboundNetworkClientProvider by UnboundNetworkClientProviderImpl(developmentApiEnabled, userAgent, ignoreSSLCertificates) { + UnboundNetworkClientProvider by UnboundNetworkClientProviderImpl( + networkStateObserver, + developmentApiEnabled, + userAgent, + ignoreSSLCertificates + ) { override val serverConfigApi: ServerConfigApi get() = ServerConfigApiImpl(unboundNetworkClient) override val remoteVersion: VersionApi get() = VersionApiImpl(unboundNetworkClient, developmentApiEnabled) override val acmeApi: ACMEApi get() = ACMEApiImpl(unboundNetworkClient) diff --git a/network/src/commonMain/kotlin/com/wire/kalium/network/utils/KaliumKtorNoNetworkHandler.kt b/network/src/commonMain/kotlin/com/wire/kalium/network/utils/KaliumKtorNoNetworkHandler.kt new file mode 100644 index 00000000000..3be8aef3423 --- /dev/null +++ b/network/src/commonMain/kotlin/com/wire/kalium/network/utils/KaliumKtorNoNetworkHandler.kt @@ -0,0 +1,59 @@ +/* + * Wire + * Copyright (C) 2023 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.network.utils + +import com.wire.kalium.network.NetworkState +import com.wire.kalium.network.NetworkStateObserver +import com.wire.kalium.network.exceptions.KaliumException +import io.ktor.client.HttpClient +import io.ktor.client.plugins.HttpClientPlugin +import io.ktor.client.request.HttpRequestPipeline +import io.ktor.util.AttributeKey + +class KaliumKtorNoNetworkHandler private constructor( + private val networkStateObserver: NetworkStateObserver +) { + class Config { + lateinit var networkStateObserver: NetworkStateObserver + } + + private fun setupHandlingNoNetwork(client: HttpClient) { + client.requestPipeline.intercept(HttpRequestPipeline.Before) { + networkStateObserver.observeNetworkState().value.let { networkState -> + if (networkState is NetworkState.ConnectedWithInternet) { + proceedWith(subject) + } else { + throw KaliumException.NoNetwork(networkState) + } + } + } + } + + companion object Plugin : HttpClientPlugin { + override val key: AttributeKey = AttributeKey("NoNetworkHandler") + + override fun prepare(block: Config.() -> Unit): KaliumKtorNoNetworkHandler { + val config = Config().apply(block) + return KaliumKtorNoNetworkHandler(config.networkStateObserver) + } + + override fun install(plugin: KaliumKtorNoNetworkHandler, scope: HttpClient) { + plugin.setupHandlingNoNetwork(scope) + } + } +} diff --git a/network/src/commonTest/kotlin/com/wire/kalium/api/ApiTest.kt b/network/src/commonTest/kotlin/com/wire/kalium/api/ApiTest.kt index cf6526dbe55..878415ac3a0 100644 --- a/network/src/commonTest/kotlin/com/wire/kalium/api/ApiTest.kt +++ b/network/src/commonTest/kotlin/com/wire/kalium/api/ApiTest.kt @@ -18,8 +18,10 @@ package com.wire.kalium.api +import com.wire.kalium.api.TestNetworkStateObserver.Companion.DEFAULT_TEST_NETWORK_STATE_OBSERVER import com.wire.kalium.network.AuthenticatedNetworkClient import com.wire.kalium.network.AuthenticatedWebSocketClient +import com.wire.kalium.network.NetworkStateObserver import com.wire.kalium.network.UnauthenticatedNetworkClient import com.wire.kalium.network.UnboundNetworkClient import com.wire.kalium.network.api.v0.authenticated.AccessTokenApiV0 @@ -37,7 +39,6 @@ import io.ktor.client.request.HttpRequestData import io.ktor.http.* import io.ktor.http.content.TextContent import io.ktor.utils.io.ByteReadChannel -import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.JsonElement import kotlin.test.assertContains import kotlin.test.assertEquals @@ -53,17 +54,17 @@ internal abstract class ApiTest { } private val json get() = KtxSerializer.json - val TEST_SESSION_NAMAGER: TestSessionManagerV0 get() = TestSessionManagerV0() + val TEST_SESSION_MANAGER: TestSessionManagerV0 get() = TestSessionManagerV0() private val loadToken: suspend () -> BearerTokens? get() = { - val session = TEST_SESSION_NAMAGER.session() + val session = TEST_SESSION_MANAGER.session() BearerTokens(accessToken = session.accessToken, refreshToken = session.refreshToken) } private val refreshToken: suspend RefreshTokensParams.() -> BearerTokens? get() = { - val newSession = TEST_SESSION_NAMAGER.updateToken(AccessTokenApiV0(client), oldTokens!!.accessToken, oldTokens!!.refreshToken) + val newSession = TEST_SESSION_MANAGER.updateToken(AccessTokenApiV0(client), oldTokens!!.accessToken, oldTokens!!.refreshToken) newSession?.let { BearerTokens(accessToken = it.accessToken, refreshToken = it.refreshToken) } @@ -82,14 +83,18 @@ internal abstract class ApiTest { responseBody: String, statusCode: HttpStatusCode, assertion: suspend (HttpRequestData.() -> Unit) = {}, - headers: Map = mutableMapOf() - ): AuthenticatedNetworkClient = mockAuthenticatedNetworkClient(ByteReadChannel(responseBody), statusCode, assertion, headers) + headers: Map = mutableMapOf(), + networkStateObserver: NetworkStateObserver = DEFAULT_TEST_NETWORK_STATE_OBSERVER + ): AuthenticatedNetworkClient = + mockAuthenticatedNetworkClient(ByteReadChannel(responseBody), statusCode, assertion, headers, networkStateObserver) fun mockAuthenticatedNetworkClient( responseBody: ByteReadChannel, statusCode: HttpStatusCode, assertion: suspend (HttpRequestData.() -> Unit) = {}, - headers: Map? + headers: Map?, + + networkStateObserver: NetworkStateObserver = DEFAULT_TEST_NETWORK_STATE_OBSERVER, ): AuthenticatedNetworkClient { val head: Map> = (headers?.let { mutableMapOf(HttpHeaders.ContentType to "application/json").plus(headers).mapValues { listOf(it.value) } @@ -106,17 +111,21 @@ internal abstract class ApiTest { } return AuthenticatedNetworkContainerV0( engine = mockEngine, - sessionManager = TEST_SESSION_NAMAGER + sessionManager = TEST_SESSION_MANAGER, + networkStateObserver = networkStateObserver, ).networkClient } - fun mockWebsocketClient(): AuthenticatedWebSocketClient { + fun mockWebsocketClient( + networkStateObserver: NetworkStateObserver = DEFAULT_TEST_NETWORK_STATE_OBSERVER, + ): AuthenticatedWebSocketClient { val mockEngine = MockEngine { TODO("It's not yet possible to mock WebSockets from the client side") } return AuthenticatedNetworkContainerV0( engine = mockEngine, - sessionManager = TEST_SESSION_NAMAGER + sessionManager = TEST_SESSION_MANAGER, + networkStateObserver = networkStateObserver ).websocketClient } @@ -124,13 +133,16 @@ internal abstract class ApiTest { responseBody: ByteReadChannel, statusCode: HttpStatusCode, assertion: (HttpRequestData.() -> Unit) = {}, - headers: Map? = null + headers: Map? = null, + + networkStateObserver: NetworkStateObserver = DEFAULT_TEST_NETWORK_STATE_OBSERVER, ): AuthenticatedNetworkClient { val mockEngine = createMockEngine(responseBody, statusCode, assertion, headers) return AuthenticatedNetworkClient( engine = mockEngine, - serverConfigDTO = TEST_SESSION_NAMAGER.serverConfig(), - bearerAuthProvider = TEST_BEARER_AUTH_PROVIDER + serverConfigDTO = TEST_SESSION_MANAGER.serverConfig(), + bearerAuthProvider = TEST_BEARER_AUTH_PROVIDER, + networkStateObserver = networkStateObserver ) } @@ -145,14 +157,19 @@ internal abstract class ApiTest { responseBody: String, statusCode: HttpStatusCode, assertion: (HttpRequestData.() -> Unit) = {}, - headers: Map? = null - ): UnauthenticatedNetworkClient = mockUnauthenticatedNetworkClient(ByteReadChannel(responseBody), statusCode, assertion, headers) + headers: Map? = null, + + networkStateObserver: NetworkStateObserver = DEFAULT_TEST_NETWORK_STATE_OBSERVER, + ): UnauthenticatedNetworkClient = + mockUnauthenticatedNetworkClient(ByteReadChannel(responseBody), statusCode, assertion, headers, networkStateObserver) private fun mockUnauthenticatedNetworkClient( responseBody: ByteReadChannel, statusCode: HttpStatusCode, assertion: (HttpRequestData.() -> Unit) = {}, - headers: Map? + headers: Map?, + + networkStateObserver: NetworkStateObserver = DEFAULT_TEST_NETWORK_STATE_OBSERVER, ): UnauthenticatedNetworkClient { val mockEngine = createMockEngine(responseBody, statusCode, assertion, headers) @@ -160,7 +177,8 @@ internal abstract class ApiTest { return UnauthenticatedNetworkContainerV0( backendLinks = TEST_BACKEND, engine = mockEngine, - proxyCredentials = null + proxyCredentials = null, + networkStateObserver = networkStateObserver ).unauthenticatedNetworkClient } @@ -173,7 +191,9 @@ internal abstract class ApiTest { ) fun mockUnauthenticatedNetworkClient( - expectedRequests: List + expectedRequests: List, + + networkStateObserver: NetworkStateObserver = DEFAULT_TEST_NETWORK_STATE_OBSERVER, ): UnauthenticatedNetworkClient { val mockEngine = MockEngine { currentRequest -> expectedRequests.forEach { request -> @@ -195,7 +215,8 @@ internal abstract class ApiTest { return UnauthenticatedNetworkContainerV0( backendLinks = TEST_BACKEND, engine = mockEngine, - proxyCredentials = null + proxyCredentials = null, + networkStateObserver = networkStateObserver ).unauthenticatedNetworkClient } @@ -210,7 +231,9 @@ internal abstract class ApiTest { responseBody: ByteArray, statusCode: HttpStatusCode, assertion: (HttpRequestData.() -> Unit) = {}, - headers: Map? = null + headers: Map? = null, + + networkStateObserver: NetworkStateObserver = DEFAULT_TEST_NETWORK_STATE_OBSERVER, ): AuthenticatedNetworkClient { val mockEngine = createMockEngine( ByteReadChannel(responseBody), @@ -220,7 +243,8 @@ internal abstract class ApiTest { ) return AuthenticatedNetworkContainerV0( engine = mockEngine, - sessionManager = TEST_SESSION_NAMAGER + sessionManager = TEST_SESSION_MANAGER, + networkStateObserver = networkStateObserver ).networkClient } @@ -235,7 +259,9 @@ internal abstract class ApiTest { responseBody: String, statusCode: HttpStatusCode, assertion: (HttpRequestData.() -> Unit) = {}, - headers: Map? = null + headers: Map? = null, + + networkStateObserver: NetworkStateObserver = DEFAULT_TEST_NETWORK_STATE_OBSERVER, ): UnboundNetworkClient { val mockEngine = createMockEngine( ByteReadChannel(responseBody), @@ -243,7 +269,10 @@ internal abstract class ApiTest { assertion, headers ) - return UnboundNetworkClient(engine = mockEngine) + return UnboundNetworkClient( + engine = mockEngine, + networkStateObserver = networkStateObserver + ) } private fun createMockEngine( diff --git a/network/src/commonTest/kotlin/com/wire/kalium/api/TestNetworkStateObserver.kt b/network/src/commonTest/kotlin/com/wire/kalium/api/TestNetworkStateObserver.kt new file mode 100644 index 00000000000..c5c7bde0944 --- /dev/null +++ b/network/src/commonTest/kotlin/com/wire/kalium/api/TestNetworkStateObserver.kt @@ -0,0 +1,36 @@ +/* + * Wire + * Copyright (C) 2023 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.api + +import com.wire.kalium.network.NetworkState +import com.wire.kalium.network.NetworkStateObserver +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +class TestNetworkStateObserver(initialState: NetworkState = NetworkState.ConnectedWithInternet) : NetworkStateObserver { + + private val networkState = MutableStateFlow(initialState) + + override fun observeNetworkState(): StateFlow = networkState + + suspend fun updateNetworkState(state: NetworkState) { networkState.emit(state) } + + companion object { + val DEFAULT_TEST_NETWORK_STATE_OBSERVER = TestNetworkStateObserver() + } +} diff --git a/network/src/commonTest/kotlin/com/wire/kalium/api/common/SessionManagerTest.kt b/network/src/commonTest/kotlin/com/wire/kalium/api/common/SessionManagerTest.kt index 2cbcf117cfa..1995b563a52 100644 --- a/network/src/commonTest/kotlin/com/wire/kalium/api/common/SessionManagerTest.kt +++ b/network/src/commonTest/kotlin/com/wire/kalium/api/common/SessionManagerTest.kt @@ -19,6 +19,7 @@ package com.wire.kalium.api.common import com.wire.kalium.api.TEST_BACKEND_CONFIG +import com.wire.kalium.api.TestNetworkStateObserver.Companion.DEFAULT_TEST_NETWORK_STATE_OBSERVER import com.wire.kalium.api.json.model.testCredentials import com.wire.kalium.network.AuthenticatedNetworkClient import com.wire.kalium.network.api.base.authenticated.AccessTokenApi @@ -166,7 +167,9 @@ class SessionManagerTest { } } - val client = AuthenticatedNetworkClient(mockEngine, sessionManager.serverConfig(), bearerAuthProvider, false) + val client = AuthenticatedNetworkClient( + DEFAULT_TEST_NETWORK_STATE_OBSERVER, mockEngine, sessionManager.serverConfig(), bearerAuthProvider, false + ) val assetApi = AssetApiV0(client) val kaliumFileSystem: FileSystem = FakeFileSystem() val tempPath = "some-dummy-path".toPath() diff --git a/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/logout/LogoutApiV0Test.kt b/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/logout/LogoutApiV0Test.kt index bd50ecb733a..bb4b22b01e3 100644 --- a/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/logout/LogoutApiV0Test.kt +++ b/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/logout/LogoutApiV0Test.kt @@ -38,7 +38,7 @@ internal class LogoutApiV0Test : ApiTest() { @Test fun givenAValidRegisterLogoutRequest_whenCallingTheRegisterLogoutEndpoint_theRequestShouldBeConfiguredCorrectly() = runTest { - val sessionManager = TEST_SESSION_NAMAGER + val sessionManager = TEST_SESSION_MANAGER val networkClient = mockAuthenticatedNetworkClient( "", statusCode = HttpStatusCode.Created, @@ -55,7 +55,7 @@ internal class LogoutApiV0Test : ApiTest() { @Test fun givenTheServerReturnsAnError_whenCallingTheLogoutEndpoint_theCorrectExceptionIsThrown() = runTest { - val sessionManager = TEST_SESSION_NAMAGER + val sessionManager = TEST_SESSION_MANAGER val networkClient = mockAuthenticatedNetworkClient( ERROR_RESPONSE.rawJson, diff --git a/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/self/SelfApiV0Test.kt b/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/self/SelfApiV0Test.kt index fc947798880..c7db79cbe44 100644 --- a/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/self/SelfApiV0Test.kt +++ b/network/src/commonTest/kotlin/com/wire/kalium/api/v0/user/self/SelfApiV0Test.kt @@ -47,7 +47,7 @@ internal class SelfApiV0Test : ApiTest() { assertPathEqual(PATH_SELF) } ) - val selfApi = SelfApiV0(networkClient, TEST_SESSION_NAMAGER) + val selfApi = SelfApiV0(networkClient, TEST_SESSION_MANAGER) val response = selfApi.getSelfInfo() assertTrue(response.isSuccessful()) assertEquals(response.value, VALID_SELF_RESPONSE.serializableData) @@ -59,7 +59,7 @@ internal class SelfApiV0Test : ApiTest() { ErrorResponseJson.valid.rawJson, statusCode = HttpStatusCode.BadRequest ) - val selfApi = SelfApiV0(networkClient, TEST_SESSION_NAMAGER) + val selfApi = SelfApiV0(networkClient, TEST_SESSION_MANAGER) val response = selfApi.getSelfInfo() assertFalse(response.isSuccessful()) assertTrue(response.kException is KaliumException.InvalidRequestError) @@ -74,11 +74,11 @@ internal class SelfApiV0Test : ApiTest() { assertion = { assertPut() assertNoQueryParams() - assertHeaderEqual(HttpHeaders.Cookie, "zuid=${TEST_SESSION_NAMAGER.session().refreshToken}") + assertHeaderEqual(HttpHeaders.Cookie, "zuid=${TEST_SESSION_MANAGER.session().refreshToken}") assertPathEqual("access/self/email") } ) - val selfApi = SelfApiV0(networkClient, TEST_SESSION_NAMAGER) + val selfApi = SelfApiV0(networkClient, TEST_SESSION_MANAGER) selfApi.updateEmailAddress("new Email").also { assertTrue(it.isSuccessful()) assertTrue(it.value) @@ -93,11 +93,11 @@ internal class SelfApiV0Test : ApiTest() { assertion = { assertPut() assertNoQueryParams() - assertHeaderEqual(HttpHeaders.Cookie, "zuid=${TEST_SESSION_NAMAGER.session().refreshToken}") + assertHeaderEqual(HttpHeaders.Cookie, "zuid=${TEST_SESSION_MANAGER.session().refreshToken}") assertPathEqual("access/self/email") } ) - val selfApi = SelfApiV0(networkClient, TEST_SESSION_NAMAGER) + val selfApi = SelfApiV0(networkClient, TEST_SESSION_MANAGER) selfApi.updateEmailAddress("new Email").also { assertTrue(it.isSuccessful()) assertFalse(it.value) @@ -117,7 +117,7 @@ internal class SelfApiV0Test : ApiTest() { assertPathEqual("access/self/email") } ) - val selfApi = SelfApiV0(networkClient, TEST_SESSION_NAMAGER) + val selfApi = SelfApiV0(networkClient, TEST_SESSION_MANAGER) selfApi.updateEmailAddress("new Email").also { assertFalse(it.isSuccessful()) assertTrue(it.kException is KaliumException.InvalidRequestError)