From 198b53edbb183d4775bd37cf34fa7e7d29fb18b2 Mon Sep 17 00:00:00 2001 From: chang Date: Sat, 5 Nov 2022 23:34:47 +0800 Subject: [PATCH 1/3] [ Bug ] Permanent lock of the mutex Using `withLock` deal with unlock automatically #119 --- .../network/plugins/RefreshTokenPlugin.kt | 43 ++++---- .../kotlin/RefreshTokenPluginTest.kt | 103 +++++++++++++++++- 2 files changed, 123 insertions(+), 23 deletions(-) diff --git a/network/src/commonMain/kotlin/dev/icerock/moko/network/plugins/RefreshTokenPlugin.kt b/network/src/commonMain/kotlin/dev/icerock/moko/network/plugins/RefreshTokenPlugin.kt index aadc94f..82d6827 100644 --- a/network/src/commonMain/kotlin/dev/icerock/moko/network/plugins/RefreshTokenPlugin.kt +++ b/network/src/commonMain/kotlin/dev/icerock/moko/network/plugins/RefreshTokenPlugin.kt @@ -16,6 +16,7 @@ import io.ktor.client.statement.request import io.ktor.http.HttpStatusCode import io.ktor.util.AttributeKey import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock class RefreshTokenPlugin( private val updateTokenHandler: suspend () -> Boolean, @@ -49,30 +50,28 @@ class RefreshTokenPlugin( return@intercept } - refreshTokenHttpPluginMutex.lock() + refreshTokenHttpPluginMutex.withLock { - // If token of the request isn't actual, then token has already been updated and - // let's just to try repeat request - if (!plugin.isCredentialsActual(subject.request)) { - refreshTokenHttpPluginMutex.unlock() - val requestBuilder = HttpRequestBuilder().takeFrom(subject.request) - val result: HttpResponse = scope.request(requestBuilder) - proceedWith(result) - return@intercept - } + // If token of the request isn't actual, then token has already been updated and + // let's just to try repeat request + if (!plugin.isCredentialsActual(subject.request)) { + val requestBuilder = HttpRequestBuilder().takeFrom(subject.request) + val result: HttpResponse = scope.request(requestBuilder) + proceedWith(result) + return@intercept + } - // Else if token of the request is actual (same as in the storage), then need to send - // refresh request. - if (plugin.updateTokenHandler.invoke()) { - // If the request refresh was successful, then let's just to try repeat request - refreshTokenHttpPluginMutex.unlock() - val requestBuilder = HttpRequestBuilder().takeFrom(subject.request) - val result: HttpResponse = scope.request(requestBuilder) - proceedWith(result) - } else { - // If the request refresh was unsuccessful - refreshTokenHttpPluginMutex.unlock() - proceedWith(subject) + // Else if token of the request is actual (same as in the storage), then need to send + // refresh request. + if (plugin.updateTokenHandler.invoke()) { + // If the request refresh was successful, then let's just to try repeat request + val requestBuilder = HttpRequestBuilder().takeFrom(subject.request) + val result: HttpResponse = scope.request(requestBuilder) + proceedWith(result) + } else { + // If the request refresh was unsuccessful + proceedWith(subject) + } } } } diff --git a/network/src/commonTest/kotlin/RefreshTokenPluginTest.kt b/network/src/commonTest/kotlin/RefreshTokenPluginTest.kt index 957db2a..3ccd4c7 100644 --- a/network/src/commonTest/kotlin/RefreshTokenPluginTest.kt +++ b/network/src/commonTest/kotlin/RefreshTokenPluginTest.kt @@ -12,8 +12,9 @@ import io.ktor.client.engine.mock.respondOk import io.ktor.client.request.get import io.ktor.client.statement.request import io.ktor.http.HttpStatusCode +import io.ktor.utils.io.errors.* +import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.runBlocking import kotlin.test.Test import kotlin.test.assertEquals @@ -78,6 +79,106 @@ class RefreshTokenPluginTest { assertEquals(expected = validToken, actual = result.request.headers[AUTH_HEADER_NAME]) } + @Test + fun `mutex not lock permanently when isCredentialsActual fail`() { + val invalidToken = "123" + val validToken = "124" + val tokenHolder = MutableStateFlow(invalidToken) + var isFirstTime = true + + val client = createMockClient( + tokenProvider = object : TokenPlugin.TokenProvider { + override fun getToken(): String? { + return tokenHolder.value + } + }, + pluginConfig = { + this.updateTokenHandler = { + tokenHolder.value = validToken + true + } + this.isCredentialsActual = { request -> + with(request.headers[AUTH_HEADER_NAME] == tokenHolder.value) { + if (isFirstTime) { + isFirstTime = false + throw IOException("simulate io Error") + } + this + } + } + }, + handler = { request -> + if (request.headers[AUTH_HEADER_NAME] == invalidToken) { + respondError(status = HttpStatusCode.Unauthorized) + } else respondOk() + } + ) + + runCatching { + runBlocking { + client.get("localhost") + } + }.onFailure { + println("simulate first request fail") + } + + val result = runBlocking { + client.get("localhost") + } + + assertEquals(expected = HttpStatusCode.OK, actual = result.status) + assertEquals(expected = validToken, actual = result.request.headers[AUTH_HEADER_NAME]) + } + + @Test + fun `mutex not lock permanently when updateTokenHandler fail`() { + val invalidToken = "123" + val validToken = "124" + val tokenHolder = MutableStateFlow(invalidToken) + var isFirstTime = true + + val client = createMockClient( + tokenProvider = object : TokenPlugin.TokenProvider { + override fun getToken(): String? { + return tokenHolder.value + } + }, + pluginConfig = { + this.updateTokenHandler = { + if (isFirstTime) { + isFirstTime = false + throw IOException("simulate io Error") + } + tokenHolder.value = validToken + true + } + this.isCredentialsActual = { request -> + request.headers[AUTH_HEADER_NAME] == tokenHolder.value + } + }, + handler = { request -> + if (request.headers[AUTH_HEADER_NAME] == invalidToken) { + respondError(status = HttpStatusCode.Unauthorized) + } else respondOk() + } + ) + + runCatching { + runBlocking { + client.get("localhost") + } + }.onFailure { + println("simulate first request fail") + } + + val result = runBlocking { + client.get("localhost") + } + + assertEquals(expected = HttpStatusCode.OK, actual = result.status) + assertEquals(expected = validToken, actual = result.request.headers[AUTH_HEADER_NAME]) + } + private fun createMockClient( tokenProvider: TokenPlugin.TokenProvider? = null, pluginConfig: RefreshTokenPlugin.Config.() -> Unit, From dac8eebd46abbc277a9804a229b105ce7240a848 Mon Sep 17 00:00:00 2001 From: Alexander Kolmachikhin Date: Mon, 9 Jan 2023 18:28:25 +0700 Subject: [PATCH 2/3] #162 change TokenProvider to fun interface --- .../moko/network/plugins/TokenPlugin.kt | 2 +- .../kotlin/RefreshTokenPluginTest.kt | 17 ++++------- .../src/commonTest/kotlin/TokenFeatureTest.kt | 30 +++++++------------ .../com/icerockdev/library/TestViewModel.kt | 4 +-- 4 files changed, 19 insertions(+), 34 deletions(-) diff --git a/network/src/commonMain/kotlin/dev/icerock/moko/network/plugins/TokenPlugin.kt b/network/src/commonMain/kotlin/dev/icerock/moko/network/plugins/TokenPlugin.kt index 5a5b2b3..9639369 100644 --- a/network/src/commonMain/kotlin/dev/icerock/moko/network/plugins/TokenPlugin.kt +++ b/network/src/commonMain/kotlin/dev/icerock/moko/network/plugins/TokenPlugin.kt @@ -39,7 +39,7 @@ class TokenPlugin private constructor( } } - interface TokenProvider { + fun interface TokenProvider { fun getToken(): String? } } diff --git a/network/src/commonTest/kotlin/RefreshTokenPluginTest.kt b/network/src/commonTest/kotlin/RefreshTokenPluginTest.kt index 957db2a..b9d6f31 100644 --- a/network/src/commonTest/kotlin/RefreshTokenPluginTest.kt +++ b/network/src/commonTest/kotlin/RefreshTokenPluginTest.kt @@ -49,11 +49,7 @@ class RefreshTokenPluginTest { val validToken = "124" val tokenHolder = MutableStateFlow(invalidToken) val client = createMockClient( - tokenProvider = object : TokenPlugin.TokenProvider { - override fun getToken(): String? { - return tokenHolder.value - } - }, + tokenProvider = { tokenHolder.value }, pluginConfig = { this.updateTokenHandler = { tokenHolder.value = validToken @@ -62,13 +58,12 @@ class RefreshTokenPluginTest { this.isCredentialsActual = { request -> request.headers[AUTH_HEADER_NAME] == tokenHolder.value } - }, - handler = { request -> - if (request.headers[AUTH_HEADER_NAME] == invalidToken) { - respondError(status = HttpStatusCode.Unauthorized) - } else respondOk() } - ) + ) { request -> + if (request.headers[AUTH_HEADER_NAME] == invalidToken) { + respondError(status = HttpStatusCode.Unauthorized) + } else respondOk() + } val result = runBlocking { client.get("localhost") diff --git a/network/src/commonTest/kotlin/TokenFeatureTest.kt b/network/src/commonTest/kotlin/TokenFeatureTest.kt index 49a1f94..7d2b5fb 100644 --- a/network/src/commonTest/kotlin/TokenFeatureTest.kt +++ b/network/src/commonTest/kotlin/TokenFeatureTest.kt @@ -18,16 +18,11 @@ class TokenFeatureTest { @Test fun `token added when exist`() { val client = createMockClient( - tokenProvider = object : TokenPlugin.TokenProvider { - override fun getToken(): String { - return "mytoken" - } - }, - handler = { request -> - if (request.headers[AUTH_HEADER_NAME] == "mytoken") respondOk() - else respondBadRequest() - } - ) + tokenProvider = { "mytoken" } + ) { request -> + if (request.headers[AUTH_HEADER_NAME] == "mytoken") respondOk() + else respondBadRequest() + } val result = runBlocking { client.get("localhost") @@ -39,16 +34,11 @@ class TokenFeatureTest { @Test fun `token not added when not exist`() { val client = createMockClient( - tokenProvider = object : TokenPlugin.TokenProvider { - override fun getToken(): String? { - return null - } - }, - handler = { request -> - if (request.headers.contains(AUTH_HEADER_NAME).not()) respondOk() - else respondBadRequest() - } - ) + tokenProvider = { null } + ) { request -> + if (request.headers.contains(AUTH_HEADER_NAME).not()) respondOk() + else respondBadRequest() + } val result = runBlocking { client.get("localhost") diff --git a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/TestViewModel.kt b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/TestViewModel.kt index cb0b7e2..64f9454 100644 --- a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/TestViewModel.kt +++ b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/TestViewModel.kt @@ -53,8 +53,8 @@ class TestViewModel : ViewModel() { install(TokenPlugin) { tokenHeaderName = "Authorization" - tokenProvider = object : TokenPlugin.TokenProvider { - override fun getToken(): String = "ed155d0a445e4b4fbd878fe1f3bc1b7f" + tokenProvider = TokenPlugin.TokenProvider { + "ed155d0a445e4b4fbd878fe1f3bc1b7f" } } } From f443bddc477de0c9e93189a8faaec817f5c50a24 Mon Sep 17 00:00:00 2001 From: Aleksey Mikhailov Date: Sun, 15 Jan 2023 22:00:44 +0600 Subject: [PATCH 3/3] #192 move http client engine dependencies to separated module --- .github/workflows/compilation-check.yml | 2 +- .github/workflows/publish.yml | 2 +- README.md | 9 +++-- gradle/libs.versions.toml | 5 +-- network-engine/build.gradle.kts | 40 +++++++++++++++++++ .../src/androidMain/AndroidManifest.xml | 2 + .../moko/network/createHttpClientEngine.kt | 0 .../moko/network/HttpClientEngineConfig.kt | 0 .../moko/network/createHttpClientEngine.kt | 4 ++ network/build.gradle.kts | 5 --- .../moko/network/NetworkConnectionError.kt | 19 +++++++-- .../moko/network/ThrowableToNSErrorMapper.kt | 21 ++++++++++ .../icerock/moko/network/isSSLException.kt | 16 ++++---- sample/mpp-library/build.gradle.kts | 4 +- settings.gradle.kts | 1 + 15 files changed, 102 insertions(+), 28 deletions(-) create mode 100644 network-engine/build.gradle.kts create mode 100755 network-engine/src/androidMain/AndroidManifest.xml rename {network => network-engine}/src/commonJvmAndroid/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt (100%) rename {network => network-engine}/src/commonMain/kotlin/dev/icerock/moko/network/HttpClientEngineConfig.kt (100%) rename {network => network-engine}/src/iosMain/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt (74%) create mode 100644 network/src/iosMain/kotlin/dev/icerock/moko/network/ThrowableToNSErrorMapper.kt diff --git a/.github/workflows/compilation-check.yml b/.github/workflows/compilation-check.yml index 0bb1691..57bc947 100644 --- a/.github/workflows/compilation-check.yml +++ b/.github/workflows/compilation-check.yml @@ -8,7 +8,7 @@ on: jobs: build: - runs-on: macOS-latest + runs-on: macOS-11 steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index e7b5d6b..7dce356 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,7 +11,7 @@ on: jobs: publish: name: Publish library at mavenCentral - runs-on: macOS-latest + runs-on: macOS-11 env: OSSRH_USER: ${{ secrets.OSSRH_USER }} OSSRH_KEY: ${{ secrets.OSSRH_KEY }} diff --git a/README.md b/README.md index c7070f1..e431a42 100755 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ buildscript { } dependencies { - classpath "dev.icerock.moko:network-generator:0.19.0" + classpath "dev.icerock.moko:network-generator:0.20.0" } } @@ -53,9 +53,10 @@ project build.gradle apply plugin: "dev.icerock.mobile.multiplatform-network-generator" dependencies { - commonMainApi("dev.icerock.moko:network:0.19.0") - commonMainApi("dev.icerock.moko:network-bignum:0.19.0") // kbignum serializer - commonMainApi("dev.icerock.moko:network-errors:0.19.0") // moko-errors integration + commonMainApi("dev.icerock.moko:network:0.20.0") + commonMainApi("dev.icerock.moko:network-engine:0.20.0") // configured HttpClientEngine + commonMainApi("dev.icerock.moko:network-bignum:0.20.0") // kbignum serializer + commonMainApi("dev.icerock.moko:network-errors:0.20.0") // moko-errors integration } ``` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9e40415..8f3f859 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ mokoResourcesVersion = "0.20.1" mokoMvvmVersion = "0.12.0" mokoErrorsVersion = "0.6.0" mokoTestVersion = "0.6.1" -mokoNetworkVersion = "0.19.0" +mokoNetworkVersion = "0.20.0" # tests espressoCoreVersion = "3.2.0" @@ -61,9 +61,6 @@ mokoResources = { module = "dev.icerock.moko:resources", version.ref = "mokoReso mokoMvvmCore = { module = "dev.icerock.moko:mvvm-core", version.ref = "mokoMvvmVersion" } mokoMvvmLiveData = { module = "dev.icerock.moko:mvvm-livedata", version.ref = "mokoMvvmVersion" } mokoErrors = { module = "dev.icerock.moko:errors", version.ref = "mokoErrorsVersion" } -mokoNetwork = { module = "dev.icerock.moko:network", version.ref = "mokoNetworkVersion" } -mokoNetworkErrors = { module = "dev.icerock.moko:network-errors", version.ref = "mokoNetworkVersion" } -mokoNetworkBignum = { module = "dev.icerock.moko:network-bignum", version.ref = "mokoNetworkVersion" } # tests espressoCore = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCoreVersion" } diff --git a/network-engine/build.gradle.kts b/network-engine/build.gradle.kts new file mode 100644 index 0000000..4920077 --- /dev/null +++ b/network-engine/build.gradle.kts @@ -0,0 +1,40 @@ +/* + * Copyright 2019 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +plugins { + id("dev.icerock.moko.gradle.multiplatform.mobile") + id("dev.icerock.moko.gradle.detekt") + id("dev.icerock.moko.gradle.publication") + id("dev.icerock.moko.gradle.stub.javadoc") + id("dev.icerock.moko.gradle.tests") +} + +kotlin { + jvm() + + sourceSets { + val commonMain by getting + + val commonJvmAndroid = create("commonJvmAndroid") { + dependsOn(commonMain) + dependencies { + api(libs.ktorClientOkHttp) + } + } + + val androidMain by getting { + dependsOn(commonJvmAndroid) + } + + val jvmMain by getting { + dependsOn(commonJvmAndroid) + } + } +} + +dependencies { + commonMainImplementation(libs.coroutines) + commonMainApi(projects.network) + iosMainApi(libs.ktorClientIos) +} diff --git a/network-engine/src/androidMain/AndroidManifest.xml b/network-engine/src/androidMain/AndroidManifest.xml new file mode 100755 index 0000000..53f792a --- /dev/null +++ b/network-engine/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/network/src/commonJvmAndroid/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt b/network-engine/src/commonJvmAndroid/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt similarity index 100% rename from network/src/commonJvmAndroid/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt rename to network-engine/src/commonJvmAndroid/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt diff --git a/network/src/commonMain/kotlin/dev/icerock/moko/network/HttpClientEngineConfig.kt b/network-engine/src/commonMain/kotlin/dev/icerock/moko/network/HttpClientEngineConfig.kt similarity index 100% rename from network/src/commonMain/kotlin/dev/icerock/moko/network/HttpClientEngineConfig.kt rename to network-engine/src/commonMain/kotlin/dev/icerock/moko/network/HttpClientEngineConfig.kt diff --git a/network/src/iosMain/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt b/network-engine/src/iosMain/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt similarity index 74% rename from network/src/iosMain/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt rename to network-engine/src/iosMain/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt index 5e2670b..9661043 100644 --- a/network/src/iosMain/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt +++ b/network-engine/src/iosMain/kotlin/dev/icerock/moko/network/createHttpClientEngine.kt @@ -6,8 +6,12 @@ package dev.icerock.moko.network import io.ktor.client.engine.HttpClientEngine import io.ktor.client.engine.darwin.Darwin +import io.ktor.client.engine.darwin.DarwinHttpRequestException actual fun createHttpClientEngine(block: HttpClientEngineConfig.() -> Unit): HttpClientEngine { + // configure darwin throwable mapper + ThrowableToNSErrorMapper.setup { (it as? DarwinHttpRequestException)?.origin } + // configure darwin engine val config = HttpClientEngineConfig().also(block) return Darwin.create { this.configureSession { diff --git a/network/build.gradle.kts b/network/build.gradle.kts index 4e03c9f..73a8165 100644 --- a/network/build.gradle.kts +++ b/network/build.gradle.kts @@ -19,9 +19,6 @@ kotlin { val commonJvmAndroid = create("commonJvmAndroid") { dependsOn(commonMain) - dependencies { - api(libs.ktorClientOkHttp) - } } val androidMain by getting { @@ -44,8 +41,6 @@ dependencies { commonMainImplementation(libs.coroutines) commonMainApi(libs.kotlinSerialization) commonMainApi(libs.ktorClient) - androidMainApi(libs.ktorClientOkHttp) - iosMainApi(libs.ktorClientIos) androidMainImplementation(libs.appCompat) diff --git a/network/src/iosMain/kotlin/dev/icerock/moko/network/NetworkConnectionError.kt b/network/src/iosMain/kotlin/dev/icerock/moko/network/NetworkConnectionError.kt index d051375..9263cba 100644 --- a/network/src/iosMain/kotlin/dev/icerock/moko/network/NetworkConnectionError.kt +++ b/network/src/iosMain/kotlin/dev/icerock/moko/network/NetworkConnectionError.kt @@ -4,11 +4,24 @@ package dev.icerock.moko.network -import io.ktor.client.engine.darwin.DarwinHttpRequestException +import platform.Foundation.NSError +import platform.Foundation.NSURLErrorCannotConnectToHost +import platform.Foundation.NSURLErrorCannotFindHost +import platform.Foundation.NSURLErrorCannotLoadFromNetwork +import platform.Foundation.NSURLErrorDomain actual fun Throwable.isNetworkConnectionError(): Boolean { - return when (this) { - is DarwinHttpRequestException -> isSSLException().not() + val nsError: NSError? = ThrowableToNSErrorMapper(this) + + return when { + this.isSSLException().not() -> true + + nsError?.domain == NSURLErrorDomain && nsError?.code in listOf( + NSURLErrorCannotConnectToHost, + NSURLErrorCannotFindHost, + NSURLErrorCannotLoadFromNetwork + ) -> true + else -> false } } diff --git a/network/src/iosMain/kotlin/dev/icerock/moko/network/ThrowableToNSErrorMapper.kt b/network/src/iosMain/kotlin/dev/icerock/moko/network/ThrowableToNSErrorMapper.kt new file mode 100644 index 0000000..6e00602 --- /dev/null +++ b/network/src/iosMain/kotlin/dev/icerock/moko/network/ThrowableToNSErrorMapper.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license. + */ + +package dev.icerock.moko.network + +import platform.Foundation.NSError +import kotlin.native.concurrent.AtomicReference + +object ThrowableToNSErrorMapper : (Throwable) -> NSError? { + private val mapperRef: AtomicReference<((Throwable) -> NSError?)?> = AtomicReference(null) + + override fun invoke(throwable: Throwable): NSError? { + return requireNotNull(mapperRef.value) { "please setup ThrowableToNSErrorMapper by call ThrowableToNSErrorMapper.setup() in iosMain or use dev.icerock.moko.network.createHttpClientEngine" } + .invoke(throwable) + } + + fun setup(block: (Throwable) -> NSError?) { + mapperRef.value = block + } +} diff --git a/network/src/iosMain/kotlin/dev/icerock/moko/network/isSSLException.kt b/network/src/iosMain/kotlin/dev/icerock/moko/network/isSSLException.kt index 087c057..d15b04e 100644 --- a/network/src/iosMain/kotlin/dev/icerock/moko/network/isSSLException.kt +++ b/network/src/iosMain/kotlin/dev/icerock/moko/network/isSSLException.kt @@ -4,9 +4,10 @@ package dev.icerock.moko.network -import io.ktor.client.engine.darwin.DarwinHttpRequestException +import platform.Foundation.NSError import platform.Foundation.NSURLErrorCannotLoadFromNetwork import platform.Foundation.NSURLErrorClientCertificateRequired +import platform.Foundation.NSURLErrorDomain import platform.Foundation.NSURLErrorSecureConnectionFailed import platform.Foundation.NSURLErrorServerCertificateHasBadDate import platform.Foundation.NSURLErrorServerCertificateHasUnknownRoot @@ -24,13 +25,14 @@ private val sslKeys = mapOf( ) actual fun Throwable.isSSLException(): Boolean { - val iosHttpException = this as? DarwinHttpRequestException ?: return false - return sslKeys.keys.contains( - iosHttpException.origin.code - ) + val nsError: NSError = ThrowableToNSErrorMapper(this) ?: return false + + return nsError.domain == NSURLErrorDomain && sslKeys.keys.contains(nsError.code) } actual fun Throwable.getSSLExceptionType(): SSLExceptionType? { - val iosHttpException = this as? DarwinHttpRequestException ?: return null - return sslKeys[iosHttpException.origin.code] + val nsError: NSError = ThrowableToNSErrorMapper(this) ?: return null + if (nsError.domain != NSURLErrorDomain) return null + + return sslKeys[nsError.code] } diff --git a/sample/mpp-library/build.gradle.kts b/sample/mpp-library/build.gradle.kts index 0c7de12..370be2d 100644 --- a/sample/mpp-library/build.gradle.kts +++ b/sample/mpp-library/build.gradle.kts @@ -25,11 +25,9 @@ dependencies { commonMainApi(libs.mokoMvvmCore) commonMainApi(libs.mokoMvvmLiveData) - commonMainApi(libs.mokoNetwork) - commonMainApi(libs.mokoNetworkErrors) - commonMainApi(libs.mokoNetworkBignum) commonMainApi(projects.network) + commonMainApi(projects.networkEngine) commonMainApi(projects.networkBignum) commonMainApi(projects.networkErrors) diff --git a/settings.gradle.kts b/settings.gradle.kts index 06cb6c1..4867c11 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,6 +17,7 @@ includeBuild("network-generator") include(":network") include(":network-errors") include(":network-bignum") +include(":network-engine") include(":sample:android-app") include(":sample:websocket-echo-server")