Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 35 additions & 7 deletions src/main/kotlin/org/phoenixframework/Defaults.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ package org.phoenixframework
import com.google.gson.FieldNamingPolicy
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.google.gson.reflect.TypeToken
import okhttp3.HttpUrl
import java.net.URL
Expand Down Expand Up @@ -65,18 +67,44 @@ object Defaults {
*/
@Suppress("UNCHECKED_CAST")
val decode: DecodeClosure = { rawMessage ->
val anyType = object : TypeToken<List<Any>>() {}.type
val result = gson.fromJson<List<Any>>(rawMessage, anyType)

var message = rawMessage
message = message.removeRange(0, 1) // remove '['

val joinRef = message.takeWhile { it != ',' } // take join ref, 'null' or '5'
message = message.removeRange(0, joinRef.length) // remove join ref
message = message.removeRange(0, 1) // remove ','

val ref = message.takeWhile { it != ',' } // take ref, 'null' or '5'
message = message.removeRange(0, ref.length) // remove ref
message = message.removeRange(0, 2) // remove ',"'

val topic = message.takeWhile { it != '"' }
message = message.removeRange(0, topic.length)
message = message.removeRange(0, 3) // remove '","'

val event = message.takeWhile { it != '"' }
message = message.removeRange(0, event.length)
message = message.removeRange(0, 2) // remove '",'

val remaining = message.removeRange(message.length - 1, message.length)

val jsonObj = gson.fromJson(remaining, JsonObject::class.java)
val response = jsonObj.get("response")
val payload = response?.let { gson.toJson(response) } ?: remaining

val anyType = object : TypeToken<Map<String, Any>>() {}.type
val result = gson.fromJson<Map<String, Any>>(remaining, anyType)

// vsn=2.0.0 message structure
// [join_ref, ref, topic, event, payload]
Message(
joinRef = result[0] as? String?,
ref = result[1] as? String ?: "",
topic = result[2] as? String ?: "",
event = result[3] as? String ?: "",
rawPayload = result[4] as? Payload ?: mapOf()
joinRef = joinRef.toIntOrNull()?.toString(),
ref = ref.toIntOrNull()?.toString() ?: "",
topic = topic,
event = event,
rawPayload = result,
payloadJson = payload
)
}

Expand Down
5 changes: 4 additions & 1 deletion src/main/kotlin/org/phoenixframework/Message.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ data class Message(
val event: String = "",

/** The raw payload of the message. It is recommended that you use `payload` instead. */
internal val rawPayload: Payload = HashMap()
internal val rawPayload: Payload = HashMap(),

/** The payload, as a json string */
val payloadJson: String = ""
) {

/** The payload of the message */
Expand Down
55 changes: 54 additions & 1 deletion src/test/kotlin/org/phoenixframework/DefaultsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ internal class DefaultsTest {
assertThat(reconnect(5)).isEqualTo(10_000)
}


@Test
internal fun `decoder converts json array into message`() {
val v2Json = """
Expand All @@ -58,6 +57,60 @@ internal class DefaultsTest {
assertThat(message.payload).isEqualTo(mapOf("message" to "Hi", "name" to "Tester"))
}

@Test
internal fun `decoder provides raw json payload`() {
val v2Json = """
[1,2,"room:lobby","shout",{"message":"Hi","name":"Tester","count":15,"ratio":0.2}]
""".trimIndent()

val message = Defaults.decode(v2Json)
assertThat(message.joinRef).isEqualTo("1")
assertThat(message.ref).isEqualTo("2")
assertThat(message.topic).isEqualTo("room:lobby")
assertThat(message.event).isEqualTo("shout")
assertThat(message.payloadJson).isEqualTo("{\"message\":\"Hi\",\"name\":\"Tester\",\"count\":15,\"ratio\":0.2}")
assertThat(message.payload).isEqualTo(mapOf(
"message" to "Hi",
"name" to "Tester",
"count" to 15.0, // Note that this is a bug and should eventually be removed
"ratio" to 0.2
))
}

@Test
internal fun `decoder decodes a status`() {
val v2Json = """
[1,2,"room:lobby","phx_reply",{"response":{"message":"Hi","name":"Tester","count":15,"ratio":0.2},"status":"ok"}]
""".trimIndent()

val message = Defaults.decode(v2Json)
assertThat(message.joinRef).isEqualTo("1")
assertThat(message.ref).isEqualTo("2")
assertThat(message.topic).isEqualTo("room:lobby")
assertThat(message.event).isEqualTo("phx_reply")
assertThat(message.payloadJson).isEqualTo("{\"message\":\"Hi\",\"name\":\"Tester\",\"count\":15,\"ratio\":0.2}")
assertThat(message.payload).isEqualTo(mapOf(
"message" to "Hi",
"name" to "Tester",
"count" to 15.0, // Note that this is a bug and should eventually be removed
"ratio" to 0.2
))
}

@Test
internal fun `decoder decodes a non-json payload`() {
val v2Json = """
[1,2,"room:lobby","phx_reply",{"response":"hello","status":"ok"}]
""".trimIndent()

val message = Defaults.decode(v2Json)
assertThat(message.payloadJson).isEqualTo("\"hello\"")
assertThat(message.payload).isEqualTo(mapOf(
"response" to "hello",
"status" to "ok"
))
}

@Test
internal fun `encode converts message into json`() {
val body = listOf(null, null, "topic", "event", mapOf("one" to "two"))
Expand Down