diff --git a/MODULE.bazel b/MODULE.bazel index b618aa493..5c54fba88 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -171,7 +171,6 @@ maven.install( "org.jetbrains.dokka:dokka-cli:1.9.10", # Library dependencies - "com.michael-bull.kotlin-result:kotlin-result-jvm:1.1.18", "com.google.code.gson:gson:2.10.1", "com.squareup.okhttp3:okhttp:{}".format(OKHTTP_VERSION), "androidx.startup:startup-runtime:1.2.0", diff --git a/examples/android/BUILD b/examples/android/BUILD index 3b1fce942..4eb01bc9e 100644 --- a/examples/android/BUILD +++ b/examples/android/BUILD @@ -13,7 +13,6 @@ _maven_deps = [ artifact("androidx.appcompat:appcompat"), artifact("androidx.activity:activity-compose"), artifact("androidx.compose.material:material"), - artifact("com.michael-bull.kotlin-result:kotlin-result-jvm"), artifact("com.google.code.gson:gson"), artifact("com.google.flatbuffers:flatbuffers-java"), artifact("androidx.annotation:annotation-jvm"), diff --git a/examples/android/MainActivity.kt b/examples/android/MainActivity.kt index aacd6a048..73b4adf6a 100644 --- a/examples/android/MainActivity.kt +++ b/examples/android/MainActivity.kt @@ -26,8 +26,6 @@ import androidx.compose.material.Text import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.testTag -import com.github.michaelbull.result.onFailure -import com.github.michaelbull.result.onSuccess import io.bitdrift.capture.Capture.Logger import io.bitdrift.capture.LogLevel import io.bitdrift.capture.common.ErrorHandler @@ -47,6 +45,7 @@ import java.io.IOException import kotlin.system.exitProcess import kotlin.time.DurationUnit import kotlin.time.toDuration +import io.bitdrift.capture.CaptureResult class MainActivity : ComponentActivity() { @@ -178,15 +177,13 @@ class MainActivity : ComponentActivity() { } fun generateTmpDeviceCode(view: View) { - Logger.createTemporaryDeviceCode(completion = { result -> - result.onSuccess { - updateDeviceCodeValue(it) + Logger.createTemporaryDeviceCode { result -> + when (result) { + is CaptureResult.Success -> updateDeviceCodeValue(result.value) + is CaptureResult.Failure -> updateDeviceCodeValue(result.error.message) } - result.onFailure { - updateDeviceCodeValue(it.message) - } - }) - } + } + } private fun updateDeviceCodeValue(deviceCode: String) { deviceCodeTextView.text = deviceCode diff --git a/platform/jvm/capture/BUILD.bazel b/platform/jvm/capture/BUILD.bazel index 1307ae832..5960d98a6 100644 --- a/platform/jvm/capture/BUILD.bazel +++ b/platform/jvm/capture/BUILD.bazel @@ -32,7 +32,6 @@ bitdrift_kt_android_library( artifact("androidx.core:core"), artifact("com.google.guava:listenablefuture"), artifact("com.google.flatbuffers:flatbuffers-java"), - artifact("com.michael-bull.kotlin-result:kotlin-result-jvm"), artifact("com.squareup.okhttp3:okhttp"), ], deps = [ @@ -44,7 +43,6 @@ bitdrift_kt_android_library( artifact("androidx.startup:startup-runtime"), artifact("androidx.core:core"), artifact("com.google.guava:listenablefuture"), - artifact("com.michael-bull.kotlin-result:kotlin-result-jvm"), artifact("com.squareup.okhttp3:okhttp"), artifact("com.google.code.findbugs:jsr305"), artifact("com.google.code.gson:gson"), diff --git a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/Capture.kt b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/Capture.kt index d34b5bff0..43a3e4a64 100644 --- a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/Capture.kt +++ b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/Capture.kt @@ -9,7 +9,6 @@ package io.bitdrift.capture import android.content.Context import android.util.Log -import com.github.michaelbull.result.Err import io.bitdrift.capture.common.IBackgroundThreadHandler import io.bitdrift.capture.common.MainThreadHandler import io.bitdrift.capture.events.span.Span @@ -288,7 +287,7 @@ object Capture { mainThreadHandler.run { completion(it) } } } ?: run { - mainThreadHandler.run { completion(Err(SdkNotStartedError)) } + mainThreadHandler.run { completion(CaptureResult.Failure(SdkNotStartedError)) } } } diff --git a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/DeviceCodeService.kt b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/DeviceCodeService.kt index 5209b2616..ed32954fa 100644 --- a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/DeviceCodeService.kt +++ b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/DeviceCodeService.kt @@ -7,7 +7,6 @@ package io.bitdrift.capture -import com.github.michaelbull.result.map import com.google.gson.annotations.SerializedName import io.bitdrift.capture.network.okhttp.HttpApiEndpoint import io.bitdrift.capture.network.okhttp.OkHttpApiClient @@ -21,8 +20,16 @@ internal class DeviceCodeService( ) { val typedRequest = DeviceCodeRequest(deviceId) - apiClient.perform(HttpApiEndpoint.GetTemporaryDeviceCode, typedRequest) { result -> - completion(result.map { it.code }) + apiClient.perform( + HttpApiEndpoint.GetTemporaryDeviceCode, + typedRequest, + ) { result -> + val mappedResult = + when (result) { + is CaptureResult.Success -> CaptureResult.Success(result.value.code) + is CaptureResult.Failure -> CaptureResult.Failure(result.error) + } + completion(mappedResult) } } } diff --git a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/LoggerImpl.kt b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/LoggerImpl.kt index 4358d6bcb..d9742b983 100644 --- a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/LoggerImpl.kt +++ b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/LoggerImpl.kt @@ -14,7 +14,6 @@ import android.content.Context import android.system.Os import androidx.annotation.VisibleForTesting import androidx.lifecycle.ProcessLifecycleOwner -import com.github.michaelbull.result.Err import io.bitdrift.capture.attributes.ClientAttributes import io.bitdrift.capture.attributes.DeviceAttributes import io.bitdrift.capture.attributes.NetworkAttributes @@ -300,7 +299,7 @@ internal class LoggerImpl( * `SharedPreferences`. */ deviceCodeService.createTemporaryDeviceCode(deviceId, completion) - } ?: completion(Err(SdkNotStartedError)) + } ?: completion(CaptureResult.Failure(SdkNotStartedError)) } private fun appExitSaveCurrentSessionId(sessionId: String? = null) { diff --git a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/Models.kt b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/Models.kt index d89d1d94c..ee1a11ce3 100644 --- a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/Models.kt +++ b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/Models.kt @@ -10,7 +10,26 @@ package io.bitdrift.capture /** * A monad for modeling success or failure operations in the Capture SDK. */ -typealias CaptureResult = com.github.michaelbull.result.Result +sealed class CaptureResult { + /** + * Represents a successful operation result within the Capture SDK. + * + * @param V the type of value returned upon success. + * @property value the result value produced by the operation. + */ + data class Success( + val value: V, + ) : CaptureResult() + + /** + * Represents a failed operation result within the Capture SDK. + * + * @property error the [Error] describing the reason for the failure. + */ + data class Failure( + val error: Error, + ) : CaptureResult() +} /** * Represents a failed operation in the Capture SDK. diff --git a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/error/ErrorReporterService.kt b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/error/ErrorReporterService.kt index 11572be52..bf8a885c0 100644 --- a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/error/ErrorReporterService.kt +++ b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/error/ErrorReporterService.kt @@ -8,10 +8,9 @@ package io.bitdrift.capture.error import android.util.Log -import com.github.michaelbull.result.onFailure -import com.github.michaelbull.result.onSuccess import com.google.gson.annotations.SerializedName import io.bitdrift.capture.ApiError +import io.bitdrift.capture.CaptureResult import io.bitdrift.capture.network.okhttp.HttpApiEndpoint import io.bitdrift.capture.network.okhttp.OkHttpApiClient import io.bitdrift.capture.providers.FieldProvider @@ -46,19 +45,29 @@ internal class ErrorReporterService( putAll(fields) } - apiClient.perform(HttpApiEndpoint.ReportSdkError, typedRequest, allFields) { result -> - result.onSuccess { - Log.i("capture", "Successfully reported error to bitdrift service") - } - result.onFailure { error -> - when (error) { - is ApiError.ServerError -> { - Log.w("capture", "Failed to report error to bitdrift service, got ${error.statusCode} response") - } - else -> { - Log.e("capture", "Failed to report error to bitdrift service: ${error.message}") - } + apiClient.perform( + HttpApiEndpoint.ReportSdkError, + typedRequest, + allFields, + ) { result -> + when (result) { + is CaptureResult.Success -> { + Log.i("capture", "Successfully reported error to bitdrift service") } + + is CaptureResult.Failure -> + when (val error = result.error) { + is ApiError.ServerError -> { + Log.w( + "capture", + "Failed to report error to bitdrift service, got ${error.statusCode} response", + ) + } + + else -> { + Log.e("capture", "Failed to report error to bitdrift service: ${error.message}") + } + } } } } diff --git a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/network/okhttp/OkHttpApiClient.kt b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/network/okhttp/OkHttpApiClient.kt index 4c6da7e1d..92f615ef1 100644 --- a/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/network/okhttp/OkHttpApiClient.kt +++ b/platform/jvm/capture/src/main/kotlin/io/bitdrift/capture/network/okhttp/OkHttpApiClient.kt @@ -8,8 +8,6 @@ package io.bitdrift.capture.network.okhttp import android.util.Log -import com.github.michaelbull.result.Err -import com.github.michaelbull.result.Ok import com.google.gson.Gson import com.google.gson.reflect.TypeToken import io.bitdrift.capture.ApiError @@ -52,19 +50,19 @@ internal class OkHttpApiClient( try { gson.toJson(body) } catch (e: Exception) { - completion(Err(e.toSerializationError())) + completion(CaptureResult.Failure(e.toSerializationError())) return } + val url = apiBaseUrl.newBuilder().addPathSegments(endpoint.path).build() val requestBuilder = Request .Builder() .url(url) .method("POST", jsonBody.toRequestBody(jsonContentType)) - headers?.let { - requestBuilder.headers(it.toHeaders()) - } + headers?.let { requestBuilder.headers(it.toHeaders()) } requestBuilder.header("x-bitdrift-api-key", apiKey) + client.newCall(requestBuilder.build()).enqueue( object : Callback { override fun onResponse( @@ -74,15 +72,14 @@ internal class OkHttpApiClient( response.use { if (response.isSuccessful) { try { - val typedResponse = - gson.fromTypedJson(response.body?.string().orEmpty()) - completion(Ok(typedResponse)) + val typedResponse = gson.fromTypedJson(response.body?.string().orEmpty()) + completion(CaptureResult.Success(typedResponse)) } catch (e: Exception) { - completion(Err(e.toSerializationError())) + completion(CaptureResult.Failure(e.toSerializationError())) } } else { val responseBody = response.body?.string() - completion(Err(ApiError.ServerError(response.code, responseBody))) + completion(CaptureResult.Failure(ApiError.ServerError(response.code, responseBody))) } Log.e("bitdrift", "done") } @@ -92,7 +89,7 @@ internal class OkHttpApiClient( call: Call, e: IOException, ) { - completion(Err(e.toNetworkError())) + completion(CaptureResult.Failure(e.toNetworkError())) } }, ) diff --git a/platform/jvm/capture/src/test/kotlin/io/bitdrift/capture/OkHttpApiClientTest.kt b/platform/jvm/capture/src/test/kotlin/io/bitdrift/capture/OkHttpApiClientTest.kt index f7a5cab00..114d5547b 100644 --- a/platform/jvm/capture/src/test/kotlin/io/bitdrift/capture/OkHttpApiClientTest.kt +++ b/platform/jvm/capture/src/test/kotlin/io/bitdrift/capture/OkHttpApiClientTest.kt @@ -7,8 +7,6 @@ package io.bitdrift.capture -import com.github.michaelbull.result.unwrap -import com.github.michaelbull.result.unwrapError import io.bitdrift.capture.network.okhttp.HttpApiEndpoint import io.bitdrift.capture.network.okhttp.OkHttpApiClient import okhttp3.mockwebserver.MockResponse @@ -30,7 +28,6 @@ class OkHttpApiClientTest { fun setup() { server = MockWebServer() server.start() - apiClient = OkHttpApiClient(server.url(""), "api-key") } @@ -43,70 +40,76 @@ class OkHttpApiClientTest { fun verifyCorrectRequestAndResponse() { // ARRANGE server.enqueue(MockResponse().setBody("{\"code\":\"123456\"}")) - val okHttpClientLatch = CountDownLatch(1) + val latch = CountDownLatch(1) + var apiResult: CaptureResult? = null // ACT - val typedRequest = DeviceCodeRequest("device-id") - var apiResult: CaptureResult? = null - apiClient.perform( + apiClient.perform( HttpApiEndpoint.GetTemporaryDeviceCode, - typedRequest, + DeviceCodeRequest("device-id"), mapOf("x-custom-header" to "header-value"), - ) { result -> - apiResult = result - okHttpClientLatch.countDown() + ) { + apiResult = it + latch.countDown() } // ASSERT val request = server.takeRequest(1, TimeUnit.SECONDS) assertThat(request?.path).isEqualTo("/v1/device/code") - assertThat(request?.headers?.get("content-type")).isEqualTo("application/json; charset=utf-8") assertThat(request?.method).isEqualTo("POST") + assertThat(request?.headers?.get("content-type")).isEqualTo("application/json; charset=utf-8") assertThat(request?.headers).contains(Pair("x-bitdrift-api-key", "api-key")) assertThat(request?.headers).contains(Pair("x-custom-header", "header-value")) - val jsonPayload = request?.body?.readString(Charset.defaultCharset()).orEmpty() - assertThat(jsonPayload).isEqualTo("{\"device_id\":\"device-id\"}") - assertThat(apiResult?.unwrap()?.code).isEqualTo("123456") + val body = request?.body?.readString(Charset.defaultCharset()).orEmpty() + assertThat(body).isEqualTo("{\"device_id\":\"device-id\"}") + + assertThat((apiResult as CaptureResult.Success).value.code).isEqualTo("123456") } @Test fun verifyOkHttpFailure() { // ARRANGE - // configure mock webserver to call onFailure server.enqueue(MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AFTER_REQUEST)) - val okHttpClientLatch = CountDownLatch(1) + val latch = CountDownLatch(1) + var apiResult: CaptureResult? = null // ACT - val typedRequest = DeviceCodeRequest("device-id") - var apiResult: CaptureResult? = null - apiClient.perform(HttpApiEndpoint.GetTemporaryDeviceCode, typedRequest) { result -> - apiResult = result - okHttpClientLatch.countDown() + apiClient.perform( + HttpApiEndpoint.GetTemporaryDeviceCode, + DeviceCodeRequest("device-id"), + ) { + apiResult = it + latch.countDown() } // ASSERT - assert(okHttpClientLatch.await(1, TimeUnit.SECONDS)) - assertThat(apiResult?.unwrapError() is ApiError.NetworkError).isTrue + assert(latch.await(1, TimeUnit.SECONDS)) + val error = (apiResult as? CaptureResult.Failure)?.error + assertThat(error is ApiError.NetworkError).isTrue } @Test fun verifyServerHttpError() { // ARRANGE server.enqueue(MockResponse().setResponseCode(500)) - val okHttpClientLatch = CountDownLatch(1) + val latch = CountDownLatch(1) + var apiResult: CaptureResult? = null // ACT - val typedRequest = DeviceCodeRequest("device-id") - var apiResult: CaptureResult? = null - apiClient.perform(HttpApiEndpoint.GetTemporaryDeviceCode, typedRequest) { result -> - apiResult = result - okHttpClientLatch.countDown() + apiClient.perform( + HttpApiEndpoint.GetTemporaryDeviceCode, + DeviceCodeRequest("device-id"), + ) { + apiResult = it + latch.countDown() } // ASSERT - assert(okHttpClientLatch.await(1, TimeUnit.SECONDS)) - val serverError = apiResult?.unwrapError() as ApiError.ServerError + assert(latch.await(1, TimeUnit.SECONDS)) + val error = (apiResult as? CaptureResult.Failure)?.error + assertThat(error).isInstanceOf(ApiError.ServerError::class.java) + val serverError = error as ApiError.ServerError assertThat(serverError.statusCode).isEqualTo(500) } @@ -114,18 +117,21 @@ class OkHttpApiClientTest { fun verifyJsonResponseError() { // ARRANGE server.enqueue(MockResponse().setBody("not a json")) - val okHttpClientLatch = CountDownLatch(1) + val latch = CountDownLatch(1) + var apiResult: CaptureResult? = null // ACT - val typedRequest = DeviceCodeRequest("device-id") - var apiResult: CaptureResult? = null - apiClient.perform(HttpApiEndpoint.GetTemporaryDeviceCode, typedRequest) { result -> - apiResult = result - okHttpClientLatch.countDown() + apiClient.perform( + HttpApiEndpoint.GetTemporaryDeviceCode, + DeviceCodeRequest("device-id"), + ) { + apiResult = it + latch.countDown() } // ASSERT - assert(okHttpClientLatch.await(1, TimeUnit.SECONDS)) - assertThat(apiResult?.unwrapError() is ApiError.SerializationError).isTrue + assert(latch.await(1, TimeUnit.SECONDS)) + val error = (apiResult as? CaptureResult.Failure)?.error + assertThat(error).isInstanceOf(ApiError.SerializationError::class.java) } } diff --git a/platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/FirstFragment.kt b/platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/FirstFragment.kt index 3609eb7bb..45aae927b 100644 --- a/platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/FirstFragment.kt +++ b/platform/jvm/gradle-test-app/src/main/java/io/bitdrift/gradletestapp/FirstFragment.kt @@ -30,9 +30,8 @@ import com.apollographql.apollo.network.okHttpClient import com.example.rocketreserver.BookTripsMutation import com.example.rocketreserver.LaunchListQuery import com.example.rocketreserver.LoginMutation -import com.github.michaelbull.result.onFailure -import com.github.michaelbull.result.onSuccess import io.bitdrift.capture.Capture.Logger +import io.bitdrift.capture.CaptureResult import io.bitdrift.capture.Error import io.bitdrift.capture.LogLevel import io.bitdrift.capture.apollo.CaptureApolloInterceptor @@ -174,14 +173,12 @@ class FirstFragment : Fragment() { private fun getTempDeviceCode(view: View) { Logger.trackSpan("createTemporaryDeviceCode", LogLevel.INFO) { - Logger.createTemporaryDeviceCode(completion = { result -> - result.onSuccess { - updateDeviceCodeValue(it) + Logger.createTemporaryDeviceCode { result -> + when (result) { + is CaptureResult.Success -> updateDeviceCodeValue(result.value) + is CaptureResult.Failure -> displayDeviceCodeError(result.error) } - result.onFailure { - displayDeviceCodeError(it) - } - }) + } } } diff --git a/test/platform/pom_checker/src/lib.rs b/test/platform/pom_checker/src/lib.rs index 979d51f42..93b5dbf2a 100644 --- a/test/platform/pom_checker/src/lib.rs +++ b/test/platform/pom_checker/src/lib.rs @@ -33,7 +33,6 @@ mod test { "com.google.code.gson:gson", "com.google.guava:listenablefuture", "com.google.flatbuffers:flatbuffers-java", - "com.michael-bull.kotlin-result:kotlin-result-jvm", "com.squareup.okhttp3:okhttp", "org.jetbrains.kotlin:kotlin-stdlib", "androidx.metrics:metrics-performance",