Skip to content

Commit

Permalink
Make serialization of Snowflake consistent (#316)
Browse files Browse the repository at this point in the history
Snowflakes are decoded as Longs but encoded as Strings. Mixing these types is allowed in JSON (and is done by Discord quite frequently) but does lead to other encoding types failing.

This commit changes snowflakes to be encoded and decoded as long values exclusively, and should fix the issue.
  • Loading branch information
BartArys authored Jun 14, 2021
1 parent 666b32a commit e558455
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 5 deletions.
4 changes: 2 additions & 2 deletions common/src/main/kotlin/entity/Snowflake.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ class Snowflake(val value: Long) : Comparable<Snowflake> {
override fun deserialize(decoder: Decoder): Snowflake = Snowflake(decoder.decodeLong())

override fun serialize(encoder: Encoder, value: Snowflake) {
encoder.encodeString(value.value.toString())
encoder.encodeLong(value.value)
}
}
}

private class SnowflakeMark(val epochMilliseconds: Long) : TimeMark() {

override fun elapsedNow(): Duration = Instant.fromEpochMilliseconds(epochMilliseconds) - Clock.System.now()
}
}
6 changes: 3 additions & 3 deletions gateway/src/test/kotlin/json/CommandTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class CommandTest {
val json = json.encodeToString(JsonObject.serializer(), buildJsonObject {
put("op", OpCode.RequestGuildMembers.code)
put("d", buildJsonObject {
put("guild_id", guildId)
put("guild_id", guildId.toLong())
put("query", query)
put("limit", limit)
})
Expand All @@ -95,8 +95,8 @@ class CommandTest {
val json = json.encodeToString(JsonObject.serializer(), buildJsonObject {
put("op", OpCode.VoiceStateUpdate.code)
put("d", buildJsonObject {
put("guild_id", guildId)
put("channel_id", channelId)
put("guild_id", guildId.toLong())
put("channel_id", channelId.toLong())
put("self_mute", selfMute)
put("self_deaf", selfDeaf)
})
Expand Down
50 changes: 50 additions & 0 deletions gateway/src/test/kotlin/json/SnowflakeTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package json

import dev.kord.common.entity.Snowflake
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.put
import kotlin.test.Test
import kotlin.test.assertEquals

class SnowflakeTest {

@Serializable
private data class SnowflakeContainer(val snowflake: Snowflake)

@Test
fun `Deserialization of Snowflake as String completes successfully`() {
val value = "1337"
val json = buildJsonObject {
put("snowflake", value)
}

val container = Json.decodeFromJsonElement<SnowflakeContainer>(json)
assertEquals(value, container.snowflake.asString)
}

@Test
fun `Deserialization of Snowflake as Long completes successfully`() {
val value = 1337L
val json = buildJsonObject {
put("snowflake", value)
}

val container = Json.decodeFromJsonElement<SnowflakeContainer>(json)
assertEquals(value, container.snowflake.value)
}

@Test
fun `Reserialization of Snowflake completes successfully`() {
val json = buildJsonObject { put("snowflake", 1337L) }

val container = Json.decodeFromJsonElement<SnowflakeContainer>(json)
val reDecodedContainer = Json.decodeFromString<SnowflakeContainer>(Json.encodeToString(container))
assertEquals(container, reDecodedContainer)
}

}

0 comments on commit e558455

Please sign in to comment.