diff --git a/gateway/api/gateway.api b/gateway/api/gateway.api index 25ff7ab3bb01..4891edf17d6b 100644 --- a/gateway/api/gateway.api +++ b/gateway/api/gateway.api @@ -1011,12 +1011,17 @@ public final class dev/kord/gateway/GuildUpdate : dev/kord/gateway/DispatchEvent public final class dev/kord/gateway/Heartbeat : dev/kord/gateway/Event { public static final field Companion Ldev/kord/gateway/Heartbeat$Companion; public static final field NewCompanion Ldev/kord/gateway/Heartbeat$NewCompanion; - public fun (J)V - public final fun component1 ()J - public final fun copy (J)Ldev/kord/gateway/Heartbeat; + public synthetic fun (J)V + public fun (Ljava/lang/Long;)V + public final synthetic fun component1 ()J + public final fun component1 ()Ljava/lang/Long; + public final synthetic fun copy (J)Ldev/kord/gateway/Heartbeat; + public final fun copy (Ljava/lang/Long;)Ldev/kord/gateway/Heartbeat; public static synthetic fun copy$default (Ldev/kord/gateway/Heartbeat;JILjava/lang/Object;)Ldev/kord/gateway/Heartbeat; + public static synthetic fun copy$default (Ldev/kord/gateway/Heartbeat;Ljava/lang/Long;ILjava/lang/Object;)Ldev/kord/gateway/Heartbeat; public fun equals (Ljava/lang/Object;)Z - public final fun getData ()J + public final synthetic fun getData ()J + public final fun getData ()Ljava/lang/Long; public fun hashCode ()I public fun toString ()Ljava/lang/String; } diff --git a/gateway/api/gateway.klib.api b/gateway/api/gateway.klib.api index 7b9f0fb7d31a..a3a0da74c31c 100644 --- a/gateway/api/gateway.klib.api +++ b/gateway/api/gateway.klib.api @@ -1237,12 +1237,17 @@ final class dev.kord.gateway/GuildUpdate : dev.kord.gateway/DispatchEvent { // d final class dev.kord.gateway/Heartbeat : dev.kord.gateway/Event { // dev.kord.gateway/Heartbeat|null[0] constructor (kotlin/Long) // dev.kord.gateway/Heartbeat.|(kotlin.Long){}[0] + constructor (kotlin/Long?) // dev.kord.gateway/Heartbeat.|(kotlin.Long?){}[0] final val data // dev.kord.gateway/Heartbeat.data|{}data[0] - final fun (): kotlin/Long // dev.kord.gateway/Heartbeat.data.|(){}[0] - - final fun component1(): kotlin/Long // dev.kord.gateway/Heartbeat.component1|component1(){}[0] - final fun copy(kotlin/Long = ...): dev.kord.gateway/Heartbeat // dev.kord.gateway/Heartbeat.copy|copy(kotlin.Long){}[0] + final fun (): kotlin/Long? // dev.kord.gateway/Heartbeat.data.|(){}[0] + final val data_ // dev.kord.gateway/Heartbeat.data_|{}data_[0] + final fun (): kotlin/Long // dev.kord.gateway/Heartbeat.data_.|(){}[0] + + final fun component1(): kotlin/Long? // dev.kord.gateway/Heartbeat.component1|component1(){}[0] + final fun component1_(): kotlin/Long // dev.kord.gateway/Heartbeat.component1_|component1_(){}[0] + final fun copy(kotlin/Long? = ...): dev.kord.gateway/Heartbeat // dev.kord.gateway/Heartbeat.copy|copy(kotlin.Long?){}[0] + final fun copy_(kotlin/Long = ...): dev.kord.gateway/Heartbeat // dev.kord.gateway/Heartbeat.copy_|copy_(kotlin.Long){}[0] final fun equals(kotlin/Any?): kotlin/Boolean // dev.kord.gateway/Heartbeat.equals|equals(kotlin.Any?){}[0] final fun hashCode(): kotlin/Int // dev.kord.gateway/Heartbeat.hashCode|hashCode(){}[0] final fun toString(): kotlin/String // dev.kord.gateway/Heartbeat.toString|toString(){}[0] diff --git a/gateway/src/commonMain/kotlin/Event.kt b/gateway/src/commonMain/kotlin/Event.kt index ee0467a8dbfa..bf7c4e5f93ec 100644 --- a/gateway/src/commonMain/kotlin/Event.kt +++ b/gateway/src/commonMain/kotlin/Event.kt @@ -7,6 +7,7 @@ import dev.kord.common.serialization.DurationInSeconds import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.datetime.Instant import kotlinx.serialization.* +import kotlinx.serialization.builtins.nullable import kotlinx.serialization.builtins.serializer import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.CompositeDecoder @@ -16,6 +17,7 @@ import kotlinx.serialization.encoding.decodeStructure import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.JsonElement import kotlin.jvm.JvmField +import kotlin.jvm.JvmName import kotlinx.serialization.DeserializationStrategy as KDeserializationStrategy private val jsonLogger = KotlinLogging.logger { } @@ -288,13 +290,40 @@ public data class ReadyData( ) @Serializable(with = Heartbeat.Serializer::class) -public data class Heartbeat(val data: Long) : Event() { +public data class Heartbeat(val data: Long?) : Event() { internal object Serializer : KSerializer { - override val descriptor = PrimitiveSerialDescriptor("dev.kord.gateway.Heartbeat", PrimitiveKind.LONG) - override fun serialize(encoder: Encoder, value: Heartbeat) = encoder.encodeLong(value.data) - override fun deserialize(decoder: Decoder) = Heartbeat(decoder.decodeLong()) + private val delegate = Long.serializer().nullable + + override val descriptor = PrimitiveSerialDescriptor("dev.kord.gateway.Heartbeat", PrimitiveKind.LONG).nullable + + override fun serialize(encoder: Encoder, value: Heartbeat) = + encoder.encodeSerializableValue(delegate, value.data) + + override fun deserialize(decoder: Decoder) = Heartbeat(decoder.decodeSerializableValue(delegate)) } + @Deprecated("Binary compatibility, keep for some releases.", level = DeprecationLevel.HIDDEN) + public constructor(data: Long) : this(data as Long?) + + @Suppress("PropertyName") + @Deprecated("Binary compatibility, keep for some releases.", level = DeprecationLevel.HIDDEN) + @get:JvmName("getData") + public val data_: Long + get() = data ?: throw NullPointerException("This heartbeat request contains a null sequence number") + + @Suppress("FunctionName") + @Deprecated("Binary compatibility, keep for some releases.", level = DeprecationLevel.HIDDEN) + @JvmName("component1") + public fun component1_(): Long = + component1() ?: throw NullPointerException("This heartbeat request contains a null sequence number") + + @Suppress("FunctionName") + @Deprecated("Binary compatibility, keep for some releases.", level = DeprecationLevel.HIDDEN) + @JvmName("copy") + public fun copy_( + data: Long = this.data ?: throw NullPointerException("This heartbeat request contains a null sequence number"), + ): Heartbeat = Heartbeat(data as Long?) + public companion object { @Suppress("DEPRECATION_ERROR") @Deprecated( diff --git a/gateway/src/commonTest/kotlin/json/SerializationTest.kt b/gateway/src/commonTest/kotlin/json/SerializationTest.kt index 55f58df8395e..23d0712136bc 100644 --- a/gateway/src/commonTest/kotlin/json/SerializationTest.kt +++ b/gateway/src/commonTest/kotlin/json/SerializationTest.kt @@ -13,6 +13,7 @@ import kotlinx.serialization.MissingFieldException import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonNull import kotlin.js.JsName +import kotlin.random.Random import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -167,6 +168,23 @@ class SerializationTest { } } + @Test + fun test_Heartbeat_Event_serialization() { + val sequenceNumbers = listOf(null, 0, -1, 1, Random.nextLong(), Long.MIN_VALUE, Long.MAX_VALUE) + sequenceNumbers.forEach { sequenceNumber -> + val heartbeat = Heartbeat(sequenceNumber) + val permutations = listOf( + jsonObjectPermutations("op" to "1", "d" to "$sequenceNumber"), + jsonObjectPermutations("op" to "1", "t" to "null", "d" to "$sequenceNumber"), + jsonObjectPermutations("op" to "1", "s" to "null", "d" to "$sequenceNumber"), + jsonObjectPermutations("op" to "1", "t" to "null", "s" to "null", "d" to "$sequenceNumber"), + ).flatten() + permutations.forEach { perm -> + assertEquals(heartbeat, Json.decodeFromString(Event.DeserializationStrategy, perm)) + } + } + } + @Test fun field_order_doesnt_matter() { val data = listOf(