From dc700692b459fc400b401d04965d62e17d27511f Mon Sep 17 00:00:00 2001 From: Julia Samol Date: Thu, 23 Feb 2023 15:13:49 +0100 Subject: [PATCH 1/3] Chore/update-ktor --- .../MichelineMichelsonV1Expression.kt | 2 +- buildSrc/src/main/java/GradleConfig.kt | 7 +- core/build.gradle | 3 +- .../internal/message/v1/V1BeaconMessage.kt | 2 +- .../internal/message/v2/V2BeaconMessage.kt | 2 +- .../internal/message/v3/V3BeaconMessage.kt | 67 +++++++++---------- .../provider/KtorHttpClientProvider.kt | 36 +++++----- .../core/internal/serializer/Json.kt | 10 +-- 8 files changed, 61 insertions(+), 68 deletions(-) diff --git a/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/operation/MichelineMichelsonV1Expression.kt b/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/operation/MichelineMichelsonV1Expression.kt index e61295a..8257a4b 100644 --- a/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/operation/MichelineMichelsonV1Expression.kt +++ b/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/operation/MichelineMichelsonV1Expression.kt @@ -106,7 +106,7 @@ public data class MichelinePrimitiveBytes(public val bytes: String) : MichelineM decoder.decodeStructure(descriptor) { val primitive = HexString(decodeStringElement(descriptor, 0)) - return MichelinePrimitiveBytes(primitive.asString(withPrefix = false)) + MichelinePrimitiveBytes(primitive.asString(withPrefix = false)) } override fun serialize(encoder: Encoder, value: MichelinePrimitiveBytes) { diff --git a/buildSrc/src/main/java/GradleConfig.kt b/buildSrc/src/main/java/GradleConfig.kt index a4aec97..4ea2350 100644 --- a/buildSrc/src/main/java/GradleConfig.kt +++ b/buildSrc/src/main/java/GradleConfig.kt @@ -10,7 +10,7 @@ object Android { object Version { const val kotlin = "1.7.20" - const val kotlinSerialization = "1.3.1" + const val kotlinSerialization = "1.4.1" const val androidxCore = "1.6.0" const val androidxAppCompat = "1.3.1" @@ -25,7 +25,7 @@ object Version { const val coroutines = "1.5.1" - const val ktor = "1.6.2" + const val ktor = "2.2.3" const val lazySodium = "5.0.2" const val jna = "5.9.0" @@ -52,7 +52,8 @@ object Dependencies { const val ktorOkHttp = "io.ktor:ktor-client-okhttp:${Version.ktor}" const val ktorJson = "io.ktor:ktor-client-json:${Version.ktor}" - const val ktorSerializationJvm = "io.ktor:ktor-client-serialization-jvm:${Version.ktor}" + const val ktorContentNegotiation = "io.ktor:ktor-client-content-negotiation:${Version.ktor}" + const val ktorSerializationJson = "io.ktor:ktor-serialization-kotlinx-json:${Version.ktor}" const val ktorLoggingJvm = "io.ktor:ktor-client-logging-jvm:${Version.ktor}" const val androidxCore = "androidx.core:core-ktx:${Version.androidxCore}" diff --git a/core/build.gradle b/core/build.gradle index 67fd97f..f51ac37 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -95,7 +95,8 @@ dependencies { // Ktor implementation(Dependencies.ktorOkHttp) implementation(Dependencies.ktorJson) - implementation(Dependencies.ktorSerializationJvm) + implementation(Dependencies.ktorContentNegotiation) + implementation(Dependencies.ktorSerializationJson) implementation(Dependencies.ktorLoggingJvm) // Lazy Sodium diff --git a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v1/V1BeaconMessage.kt b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v1/V1BeaconMessage.kt index a585dff..8e0b882 100644 --- a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v1/V1BeaconMessage.kt +++ b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v1/V1BeaconMessage.kt @@ -128,7 +128,7 @@ public data class ErrorV1BeaconResponse( val beaconId = decodeStringElement(descriptor, 3) val errorType = decodeSerializableElement(descriptor, 4, beaconErrorSerializer) - return ErrorV1BeaconResponse(version, id, beaconId, errorType) + ErrorV1BeaconResponse(version, id, beaconId, errorType) } override fun serialize(jsonEncoder: JsonEncoder, value: ErrorV1BeaconResponse) { diff --git a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v2/V2BeaconMessage.kt b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v2/V2BeaconMessage.kt index 2dcdff6..26055d0 100644 --- a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v2/V2BeaconMessage.kt +++ b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v2/V2BeaconMessage.kt @@ -152,7 +152,7 @@ public data class ErrorV2BeaconResponse( val senderId = decodeStringElement(descriptor, 3) val errorType = decodeSerializableElement(descriptor, 4, beaconErrorSerializer) - return ErrorV2BeaconResponse(version, id, senderId, errorType) + ErrorV2BeaconResponse(version, id, senderId, errorType) } override fun serialize(jsonEncoder: JsonEncoder, value: ErrorV2BeaconResponse) { diff --git a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v3/V3BeaconMessage.kt b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v3/V3BeaconMessage.kt index 9bd61ae..ba82553 100644 --- a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v3/V3BeaconMessage.kt +++ b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v3/V3BeaconMessage.kt @@ -5,8 +5,7 @@ import it.airgap.beaconsdk.core.data.BeaconError import it.airgap.beaconsdk.core.data.Connection import it.airgap.beaconsdk.core.internal.blockchain.BlockchainRegistry import it.airgap.beaconsdk.core.internal.message.VersionedBeaconMessage -import it.airgap.beaconsdk.core.internal.utils.KJsonSerializer -import it.airgap.beaconsdk.core.internal.utils.blockchainRegistry +import it.airgap.beaconsdk.core.internal.utils.* import it.airgap.beaconsdk.core.message.* import it.airgap.beaconsdk.core.scope.BeaconScope import kotlinx.serialization.* @@ -15,10 +14,7 @@ import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.descriptors.element import kotlinx.serialization.encoding.decodeStructure import kotlinx.serialization.encoding.encodeStructure -import kotlinx.serialization.json.JsonClassDiscriminator -import kotlinx.serialization.json.JsonDecoder -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonEncoder +import kotlinx.serialization.json.* @OptIn(ExperimentalSerializationApi::class) @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) @@ -128,6 +124,7 @@ public data class PermissionV3BeaconRequestContent( Serializer(beaconScope) } + @OptIn(ExperimentalSerializationApi::class) internal class Serializer(private val blockchainRegistry: BlockchainRegistry) : KJsonSerializer { constructor(beaconScope: BeaconScope? = null) : this(blockchainRegistry(beaconScope)) @@ -136,13 +133,12 @@ public data class PermissionV3BeaconRequestContent( element("blockchainData") } - override fun deserialize(jsonDecoder: JsonDecoder, jsonElement: JsonElement): PermissionV3BeaconRequestContent = - jsonDecoder.decodeStructure(descriptor) { - val blockchainIdentifier = decodeStringElement(descriptor, 0) - val blockchainData = decodeSerializableElement(descriptor, 1, BlockchainData.serializer(blockchainRegistry, blockchainIdentifier)) + override fun deserialize(jsonDecoder: JsonDecoder, jsonElement: JsonElement): PermissionV3BeaconRequestContent { + val blockchainIdentifier = jsonElement.jsonObject.getString(descriptor.getElementName(0)) + val blockchainData = jsonElement.jsonObject.getSerializable(descriptor.getElementName(1), jsonDecoder, BlockchainData.serializer(blockchainRegistry, blockchainIdentifier)) - PermissionV3BeaconRequestContent(blockchainIdentifier, blockchainData) - } + return PermissionV3BeaconRequestContent(blockchainIdentifier, blockchainData) + } override fun serialize(jsonEncoder: JsonEncoder, value: PermissionV3BeaconRequestContent) = jsonEncoder.encodeStructure(descriptor) { @@ -209,6 +205,7 @@ public data class BlockchainV3BeaconRequestContent( Serializer(beaconScope) } + @OptIn(ExperimentalSerializationApi::class) internal class Serializer(private val blockchainRegistry: BlockchainRegistry) : KJsonSerializer { constructor(beaconScope: BeaconScope? = null) : this(blockchainRegistry(beaconScope)) @@ -218,14 +215,13 @@ public data class BlockchainV3BeaconRequestContent( element("blockchainData") } - override fun deserialize(jsonDecoder: JsonDecoder, jsonElement: JsonElement): BlockchainV3BeaconRequestContent = - jsonDecoder.decodeStructure(descriptor) { - val blockchainIdentifier = decodeStringElement(descriptor, 0) - val accountId = decodeStringElement(descriptor, 1) - val blockchainData = decodeSerializableElement(descriptor, 2, BlockchainData.serializer(blockchainRegistry, blockchainIdentifier)) + override fun deserialize(jsonDecoder: JsonDecoder, jsonElement: JsonElement): BlockchainV3BeaconRequestContent { + val blockchainIdentifier = jsonElement.jsonObject.getString(descriptor.getElementName(0)) + val accountId = jsonElement.jsonObject.getString(descriptor.getElementName(1)) + val blockchainData = jsonElement.jsonObject.getSerializable(descriptor.getElementName(2), jsonDecoder, BlockchainData.serializer(blockchainRegistry, blockchainIdentifier)) - BlockchainV3BeaconRequestContent(blockchainIdentifier, accountId, blockchainData) - } + return BlockchainV3BeaconRequestContent(blockchainIdentifier, accountId, blockchainData) + } override fun serialize(jsonEncoder: JsonEncoder, value: BlockchainV3BeaconRequestContent) = jsonEncoder.encodeStructure(descriptor) { @@ -291,6 +287,7 @@ public data class PermissionV3BeaconResponseContent( Serializer(beaconScope) } + @OptIn(ExperimentalSerializationApi::class) internal class Serializer(private val blockchainRegistry: BlockchainRegistry) : KJsonSerializer { constructor(beaconScope: BeaconScope? = null) : this(blockchainRegistry(beaconScope)) @@ -299,13 +296,12 @@ public data class PermissionV3BeaconResponseContent( element("blockchainData") } - override fun deserialize(jsonDecoder: JsonDecoder, jsonElement: JsonElement): PermissionV3BeaconResponseContent = - jsonDecoder.decodeStructure(descriptor) { - val blockchainIdentifier = decodeStringElement(descriptor, 0) - val blockchainData = decodeSerializableElement(descriptor, 1, BlockchainData.serializer(blockchainRegistry, blockchainIdentifier)) + override fun deserialize(jsonDecoder: JsonDecoder, jsonElement: JsonElement): PermissionV3BeaconResponseContent { + val blockchainIdentifier = jsonElement.jsonObject.getString(descriptor.getElementName(0)) + val blockchainData = jsonElement.jsonObject.getSerializable(descriptor.getElementName(1), jsonDecoder, BlockchainData.serializer(blockchainRegistry, blockchainIdentifier)) - PermissionV3BeaconResponseContent(blockchainIdentifier, blockchainData) - } + return PermissionV3BeaconResponseContent(blockchainIdentifier, blockchainData) + } override fun serialize(jsonEncoder: JsonEncoder, value: PermissionV3BeaconResponseContent) = jsonEncoder.encodeStructure(descriptor) { @@ -364,6 +360,7 @@ public data class BlockchainV3BeaconResponseContent( Serializer(beaconScope) } + @OptIn(ExperimentalSerializationApi::class) internal class Serializer(private val blockchainRegistry: BlockchainRegistry) : KJsonSerializer { constructor(beaconScope: BeaconScope? = null) : this(blockchainRegistry(beaconScope)) @@ -372,13 +369,12 @@ public data class BlockchainV3BeaconResponseContent( element("blockchainData") } - override fun deserialize(jsonDecoder: JsonDecoder, jsonElement: JsonElement): BlockchainV3BeaconResponseContent = - jsonDecoder.decodeStructure(descriptor) { - val blockchainIdentifier = decodeStringElement(descriptor, 0) - val blockchainData = decodeSerializableElement(descriptor, 1, BlockchainData.serializer(blockchainRegistry, blockchainIdentifier)) + override fun deserialize(jsonDecoder: JsonDecoder, jsonElement: JsonElement): BlockchainV3BeaconResponseContent { + val blockchainIdentifier = jsonElement.jsonObject.getString(descriptor.getElementName(0)) + val blockchainData = jsonElement.jsonObject.getSerializable(descriptor.getElementName(1), jsonDecoder, BlockchainData.serializer(blockchainRegistry, blockchainIdentifier)) - BlockchainV3BeaconResponseContent(blockchainIdentifier, blockchainData) - } + return BlockchainV3BeaconResponseContent(blockchainIdentifier, blockchainData) + } override fun serialize(jsonEncoder: JsonEncoder, value: BlockchainV3BeaconResponseContent) = jsonEncoder.encodeStructure(descriptor) { @@ -432,6 +428,7 @@ public data class ErrorV3BeaconResponseContent( Serializer(beaconScope) } + @OptIn(ExperimentalSerializationApi::class) internal class Serializer(private val blockchainRegistry: BlockchainRegistry) : KJsonSerializer { constructor(beaconScope: BeaconScope? = null) : this(blockchainRegistry(beaconScope)) @@ -447,10 +444,10 @@ public data class ErrorV3BeaconResponseContent( override fun deserialize( jsonDecoder: JsonDecoder, jsonElement: JsonElement, - ): ErrorV3BeaconResponseContent = jsonDecoder.decodeStructure(descriptor) { - val blockchainIdentifier = runCatching { decodeStringElement(descriptor, 0) }.getOrNull() - val errorType = decodeSerializableElement(descriptor, 1, beaconErrorSerializer(blockchainIdentifier)) - val description = runCatching { decodeStringElement(descriptor, 2) }.getOrNull() + ): ErrorV3BeaconResponseContent { + val blockchainIdentifier = jsonElement.jsonObject.getStringOrNull(descriptor.getElementName(0)) + val errorType = jsonElement.jsonObject.getSerializable(descriptor.getElementName(1), jsonDecoder, beaconErrorSerializer(blockchainIdentifier)) + val description = jsonElement.jsonObject.getStringOrNull(descriptor.getElementName(2)) return ErrorV3BeaconResponseContent(errorType, description) } diff --git a/core/src/main/java/it/airgap/beaconsdk/core/internal/network/provider/KtorHttpClientProvider.kt b/core/src/main/java/it/airgap/beaconsdk/core/internal/network/provider/KtorHttpClientProvider.kt index 8fb9aad..15709dd 100644 --- a/core/src/main/java/it/airgap/beaconsdk/core/internal/network/provider/KtorHttpClientProvider.kt +++ b/core/src/main/java/it/airgap/beaconsdk/core/internal/network/provider/KtorHttpClientProvider.kt @@ -1,32 +1,28 @@ package it.airgap.beaconsdk.core.internal.network.provider import io.ktor.client.* +import io.ktor.client.call.* import io.ktor.client.engine.okhttp.* -import io.ktor.client.features.* -import io.ktor.client.features.json.* -import io.ktor.client.features.json.serializer.* -import io.ktor.client.features.logging.* +import io.ktor.client.plugins.* +import io.ktor.client.plugins.contentnegotiation.* +import io.ktor.client.plugins.logging.* import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* -import it.airgap.beaconsdk.core.internal.utils.decodeFromString +import io.ktor.serialization.kotlinx.json.* import it.airgap.beaconsdk.core.internal.utils.logDebug import it.airgap.beaconsdk.core.network.data.HttpHeader import it.airgap.beaconsdk.core.network.data.HttpParameter import it.airgap.beaconsdk.core.network.exception.HttpException import it.airgap.beaconsdk.core.network.provider.HttpClientProvider -import it.airgap.beaconsdk.core.network.provider.HttpProvider import it.airgap.beaconsdk.core.scope.BeaconScope -import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json -import kotlinx.serialization.json.JsonElement -import kotlin.reflect.KClass internal class KtorHttpClientProvider(private val json: Json, private val beaconScope: BeaconScope) : HttpClientProvider { private val ktorClient by lazy { HttpClient(OkHttp) { - install(JsonFeature) { - serializer = KotlinxSerializer(json) + install(ContentNegotiation) { + json(json) } install(HttpTimeout) @@ -59,7 +55,7 @@ internal class KtorHttpClientProvider(private val json: Json, private val beacon body: String?, timeoutMillis: Long?, ): String = request(HttpMethod.Post, baseUrl, endpoint, headers, parameters, timeoutMillis) { - body?.let { setBodyAsText(it) } + body?.let { setBody(it) } } @Suppress("UNCHECKED_CAST") @@ -71,9 +67,10 @@ internal class KtorHttpClientProvider(private val json: Json, private val beacon body: String?, timeoutMillis: Long?, ): String = request(HttpMethod.Put, baseUrl, endpoint, headers, parameters, timeoutMillis) { - body?.let { setBodyAsText(it) } + body?.let { setBody(it) } } + @Throws(HttpException::class) private suspend fun request( method: HttpMethod, baseUrl: String, @@ -90,17 +87,19 @@ internal class KtorHttpClientProvider(private val json: Json, private val beacon headers(httpHeaders) parameters(httpParameters) + expectSuccess = true + timeoutMillis?.let { timeout(it) } block(this) - } + }.body() } catch (e: ClientRequestException) { throw decodeError(e) } - private suspend fun decodeError(error: ClientRequestException): Throwable = + private suspend fun decodeError(error: ClientRequestException): HttpException = try { - val response = error.response.readText(Charsets.UTF_8) + val response = error.response.body() HttpException.Serialized(response) } catch (e: Exception) { HttpException.Failure(error.response.status.value, cause = error) @@ -108,11 +107,6 @@ internal class KtorHttpClientProvider(private val json: Json, private val beacon private fun apiUrl(baseUrl: String, endpoint: String): String = "$baseUrl/${endpoint.trimStart('/')}" - private fun HttpRequestBuilder.setBodyAsText(body: String) { - this.body = json.decodeFromString(body) - } - - private fun HttpRequestBuilder.headers(headers: List) { headers.forEach { header(it.first, it.second) } } diff --git a/core/src/main/java/it/airgap/beaconsdk/core/internal/serializer/Json.kt b/core/src/main/java/it/airgap/beaconsdk/core/internal/serializer/Json.kt index 961be60..a6dbfce 100644 --- a/core/src/main/java/it/airgap/beaconsdk/core/internal/serializer/Json.kt +++ b/core/src/main/java/it/airgap/beaconsdk/core/internal/serializer/Json.kt @@ -60,13 +60,13 @@ private fun serializersModule( subclass(DisconnectV3BeaconMessageContent::class, DisconnectV3BeaconMessageContent.serializer()) } - contextual(PermissionV3BeaconRequestContent.Serializer(blockchainRegistry)) - contextual(PermissionV3BeaconResponseContent.Serializer(blockchainRegistry)) + contextual(PermissionV3BeaconRequestContent.serializer(blockchainRegistry)) + contextual(PermissionV3BeaconResponseContent.serializer(blockchainRegistry)) - contextual(BlockchainV3BeaconRequestContent.Serializer(blockchainRegistry)) - contextual(BlockchainV3BeaconResponseContent.Serializer(blockchainRegistry)) + contextual(BlockchainV3BeaconRequestContent.serializer(blockchainRegistry)) + contextual(BlockchainV3BeaconResponseContent.serializer(blockchainRegistry)) - contextual(ErrorV3BeaconResponseContent.Serializer(blockchainRegistry)) + contextual(ErrorV3BeaconResponseContent.serializer(blockchainRegistry)) // -- pairing -- From 401fc6f8f775b204dcad98775c8f40569fd54e5d Mon Sep 17 00:00:00 2001 From: Julia Samol Date: Thu, 23 Feb 2023 15:24:52 +0100 Subject: [PATCH 2/3] Chore/update-tezos-networks --- .../blockchain/tezos/data/TezosNetwork.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/TezosNetwork.kt b/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/TezosNetwork.kt index c9d4125..24da4ec 100644 --- a/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/TezosNetwork.kt +++ b/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/TezosNetwork.kt @@ -164,6 +164,7 @@ public sealed class TezosNetwork : Network() { } } + @Deprecated("'Ithacanet' is no longer a maintained Tezos test network and will be removed from Beacon in future versions.") @Serializable @SerialName(Ithacanet.TYPE) public data class Ithacanet( @@ -178,6 +179,7 @@ public sealed class TezosNetwork : Network() { } } + @Deprecated("'Jakartanet' is no longer a maintained Tezos test network and will be removed from Beacon in future versions.") @Serializable @SerialName(Jakartanet.TYPE) public data class Jakartanet( @@ -206,6 +208,34 @@ public sealed class TezosNetwork : Network() { } } + @Serializable + @SerialName(Limanet.TYPE) + public data class Limanet( + override val name: String? = null, + override val rpcUrl: String? = null, + ) : TezosNetwork() { + @Transient + override val type: String = TYPE + + public companion object { + internal const val TYPE = "limanet" + } + } + + @Serializable + @SerialName(Mumbainet.TYPE) + public data class Mumbainet( + override val name: String? = null, + override val rpcUrl: String? = null, + ) : TezosNetwork() { + @Transient + override val type: String = TYPE + + public companion object { + internal const val TYPE = "mumbainet" + } + } + @Serializable @SerialName(Custom.TYPE) public data class Custom( From 1b1af4fb456db71ce2326ee3f87df0a56179ad5a Mon Sep 17 00:00:00 2001 From: Julia Samol Date: Thu, 23 Feb 2023 16:51:24 +0100 Subject: [PATCH 3/3] Release/3.2.4 --- .../MichelineMichelsonV1Expression.kt | 17 ++++--- buildSrc/src/main/java/GradleConfig.kt | 4 +- .../internal/message/v1/V1BeaconMessage.kt | 38 ++++++++++------ .../internal/message/v2/V2BeaconMessage.kt | 44 ++++++++++++------- .../internal/message/v3/V3BeaconMessage.kt | 1 - 5 files changed, 66 insertions(+), 38 deletions(-) diff --git a/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/operation/MichelineMichelsonV1Expression.kt b/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/operation/MichelineMichelsonV1Expression.kt index 8257a4b..088ec79 100644 --- a/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/operation/MichelineMichelsonV1Expression.kt +++ b/blockchain-tezos/src/main/java/it/airgap/beaconsdk/blockchain/tezos/data/operation/MichelineMichelsonV1Expression.kt @@ -10,10 +10,7 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.descriptors.element -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.encoding.decodeStructure -import kotlinx.serialization.encoding.encodeStructure +import kotlinx.serialization.encoding.* import kotlinx.serialization.json.* /** @@ -93,6 +90,7 @@ public data class MichelinePrimitiveString(public val string: String) : Michelin public data class MichelinePrimitiveBytes(public val bytes: String) : MichelineMichelsonV1Expression() { public companion object {} + @OptIn(ExperimentalSerializationApi::class) internal object Serializer : KSerializer { object Field { const val BYTES = "bytes" @@ -104,7 +102,16 @@ public data class MichelinePrimitiveBytes(public val bytes: String) : MichelineM override fun deserialize(decoder: Decoder): MichelinePrimitiveBytes = decoder.decodeStructure(descriptor) { - val primitive = HexString(decodeStringElement(descriptor, 0)) + var primitive: HexString? = null + while (true) { + when (decodeElementIndex(descriptor)) { + 0 -> primitive = HexString(decodeStringElement(descriptor, 0)) + CompositeDecoder.DECODE_DONE -> break + else -> continue + } + } + + primitive ?: failWithMissingField(descriptor.getElementName(0)) MichelinePrimitiveBytes(primitive.asString(withPrefix = false)) } diff --git a/buildSrc/src/main/java/GradleConfig.kt b/buildSrc/src/main/java/GradleConfig.kt index 4ea2350..7c9b645 100644 --- a/buildSrc/src/main/java/GradleConfig.kt +++ b/buildSrc/src/main/java/GradleConfig.kt @@ -3,8 +3,8 @@ object Android { const val minSdk = 21 const val targetSdk = 33 - const val versionCode = 31 - const val versionName = "3.2.3" + const val versionCode = 33 + const val versionName = "3.2.4" } object Version { diff --git a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v1/V1BeaconMessage.kt b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v1/V1BeaconMessage.kt index 8e0b882..276f50b 100644 --- a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v1/V1BeaconMessage.kt +++ b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v1/V1BeaconMessage.kt @@ -18,8 +18,7 @@ import kotlinx.serialization.* import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.descriptors.element -import kotlinx.serialization.encoding.decodeStructure -import kotlinx.serialization.encoding.encodeStructure +import kotlinx.serialization.encoding.* import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonEncoder @@ -106,7 +105,7 @@ public data class ErrorV1BeaconResponse( public fun serializer(beaconScope: BeaconScope? = null): KSerializer = Serializer(beaconScope) } - internal class Serializer(blockchainRegistry: BlockchainRegistry, compat: Compat) : KJsonSerializer { + internal class Serializer(blockchainRegistry: BlockchainRegistry, compat: Compat) : KSerializer { constructor(beaconScope: BeaconScope? = null) : this(blockchainRegistry(beaconScope), compat(beaconScope)) private val beaconErrorSerializer: KSerializer = BeaconError.serializer(blockchainRegistry, compat.versioned.blockchain.identifier) @@ -119,20 +118,33 @@ public data class ErrorV1BeaconResponse( element("errorType", beaconErrorSerializer.descriptor) } - override fun deserialize( - jsonDecoder: JsonDecoder, - jsonElement: JsonElement, - ): ErrorV1BeaconResponse = jsonDecoder.decodeStructure(descriptor) { - val version = decodeStringElement(descriptor, 1) - val id = decodeStringElement(descriptor, 2) - val beaconId = decodeStringElement(descriptor, 3) - val errorType = decodeSerializableElement(descriptor, 4, beaconErrorSerializer) + override fun deserialize(decoder: Decoder): ErrorV1BeaconResponse = decoder.decodeStructure(descriptor) { + var version: String? = null + var id: String? = null + var beaconId: String? = null + var errorType: BeaconError? = null + + while (true) { + when (decodeElementIndex(descriptor)) { + 1 -> version = decodeStringElement(descriptor, 1) + 2 -> id = decodeStringElement(descriptor, 2) + 3 -> beaconId = decodeStringElement(descriptor, 3) + 4 -> errorType = decodeSerializableElement(descriptor, 4, beaconErrorSerializer) + CompositeDecoder.DECODE_DONE -> break + else -> continue + } + } + + version ?: failWithMissingField(descriptor.getElementName(1)) + id ?: failWithMissingField(descriptor.getElementName(2)) + beaconId ?: failWithMissingField(descriptor.getElementName(3)) + errorType ?: failWithMissingField(descriptor.getElementName(4)) ErrorV1BeaconResponse(version, id, beaconId, errorType) } - override fun serialize(jsonEncoder: JsonEncoder, value: ErrorV1BeaconResponse) { - jsonEncoder.encodeStructure(descriptor) { + override fun serialize(encoder: Encoder, value: ErrorV1BeaconResponse) { + encoder.encodeStructure(descriptor) { with(value) { encodeStringElement(descriptor, 0, type) encodeStringElement(descriptor, 1, version) diff --git a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v2/V2BeaconMessage.kt b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v2/V2BeaconMessage.kt index 26055d0..3abf300 100644 --- a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v2/V2BeaconMessage.kt +++ b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v2/V2BeaconMessage.kt @@ -6,11 +6,9 @@ import it.airgap.beaconsdk.core.data.Connection import it.airgap.beaconsdk.core.internal.blockchain.BlockchainRegistry import it.airgap.beaconsdk.core.internal.compat.Compat import it.airgap.beaconsdk.core.internal.compat.VersionedCompat +import it.airgap.beaconsdk.core.internal.data.HexString import it.airgap.beaconsdk.core.internal.message.VersionedBeaconMessage -import it.airgap.beaconsdk.core.internal.utils.KJsonSerializer -import it.airgap.beaconsdk.core.internal.utils.blockchainRegistry -import it.airgap.beaconsdk.core.internal.utils.compat -import it.airgap.beaconsdk.core.internal.utils.getString +import it.airgap.beaconsdk.core.internal.utils.* import it.airgap.beaconsdk.core.message.AcknowledgeBeaconResponse import it.airgap.beaconsdk.core.message.BeaconMessage import it.airgap.beaconsdk.core.message.DisconnectBeaconMessage @@ -20,8 +18,7 @@ import kotlinx.serialization.* import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.descriptors.element -import kotlinx.serialization.encoding.decodeStructure -import kotlinx.serialization.encoding.encodeStructure +import kotlinx.serialization.encoding.* import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonEncoder @@ -130,7 +127,7 @@ public data class ErrorV2BeaconResponse( Serializer(beaconScope) } - internal class Serializer(blockchainRegistry: BlockchainRegistry, compat: Compat) : KJsonSerializer { + internal class Serializer(blockchainRegistry: BlockchainRegistry, compat: Compat) : KSerializer { constructor(beaconScope: BeaconScope? = null) : this(blockchainRegistry(beaconScope), compat(beaconScope)) private val beaconErrorSerializer: KSerializer = BeaconError.serializer(blockchainRegistry, compat.versioned.blockchain.identifier) @@ -143,20 +140,33 @@ public data class ErrorV2BeaconResponse( element("errorType", beaconErrorSerializer.descriptor) } - override fun deserialize( - jsonDecoder: JsonDecoder, - jsonElement: JsonElement, - ): ErrorV2BeaconResponse = jsonDecoder.decodeStructure(descriptor) { - val version = decodeStringElement(descriptor, 1) - val id = decodeStringElement(descriptor, 2) - val senderId = decodeStringElement(descriptor, 3) - val errorType = decodeSerializableElement(descriptor, 4, beaconErrorSerializer) + override fun deserialize(decoder: Decoder): ErrorV2BeaconResponse = decoder.decodeStructure(descriptor) { + var version: String? = null + var id: String? = null + var senderId: String? = null + var errorType: BeaconError? = null + + while (true) { + when (decodeElementIndex(descriptor)) { + 1 -> version = decodeStringElement(descriptor, 1) + 2 -> id = decodeStringElement(descriptor, 2) + 3 -> senderId = decodeStringElement(descriptor, 3) + 4 -> errorType = decodeSerializableElement(descriptor, 4, beaconErrorSerializer) + CompositeDecoder.DECODE_DONE -> break + else -> continue + } + } + + version ?: failWithMissingField(descriptor.getElementName(1)) + id ?: failWithMissingField(descriptor.getElementName(2)) + senderId ?: failWithMissingField(descriptor.getElementName(3)) + errorType ?: failWithMissingField(descriptor.getElementName(4)) ErrorV2BeaconResponse(version, id, senderId, errorType) } - override fun serialize(jsonEncoder: JsonEncoder, value: ErrorV2BeaconResponse) { - jsonEncoder.encodeStructure(descriptor) { + override fun serialize(encoder: Encoder, value: ErrorV2BeaconResponse) { + encoder.encodeStructure(descriptor) { with(value) { encodeStringElement(descriptor, 0, type) encodeStringElement(descriptor, 1, version) diff --git a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v3/V3BeaconMessage.kt b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v3/V3BeaconMessage.kt index ba82553..96d0053 100644 --- a/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v3/V3BeaconMessage.kt +++ b/core/src/main/java/it/airgap/beaconsdk/core/internal/message/v3/V3BeaconMessage.kt @@ -12,7 +12,6 @@ import kotlinx.serialization.* import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.descriptors.element -import kotlinx.serialization.encoding.decodeStructure import kotlinx.serialization.encoding.encodeStructure import kotlinx.serialization.json.*