1
1
package org.xmtp.android.library.codecs
2
2
3
3
import com.google.gson.GsonBuilder
4
+ import com.google.gson.JsonDeserializationContext
5
+ import com.google.gson.JsonDeserializer
6
+ import com.google.gson.JsonElement
7
+ import com.google.gson.JsonObject
8
+ import com.google.gson.JsonSerializationContext
9
+ import com.google.gson.JsonSerializer
4
10
import com.google.protobuf.kotlin.toByteStringUtf8
11
+ import java.lang.reflect.Type
5
12
6
13
val ContentTypeReaction = ContentTypeIdBuilder .builderFromAuthorityId(
7
14
" xmtp.org" ,
@@ -17,47 +24,109 @@ data class Reaction(
17
24
val schema : ReactionSchema ,
18
25
)
19
26
20
- enum class ReactionAction {
21
- added, removed
27
+ sealed class ReactionAction {
28
+ object Removed : ReactionAction()
29
+ object Added : ReactionAction()
30
+ object Unknown : ReactionAction()
22
31
}
23
32
24
- enum class ReactionSchema {
25
- unicode, shortcode, custom
33
+ sealed class ReactionSchema {
34
+ object Unicode : ReactionSchema()
35
+ object Shortcode : ReactionSchema()
36
+ object Custom : ReactionSchema()
37
+ object Unknown : ReactionSchema()
38
+ }
39
+
40
+ private fun getReactionSchema (schema : String ): ReactionSchema {
41
+ return when (schema) {
42
+ " unicode" -> ReactionSchema .Unicode
43
+ " shortcode" -> ReactionSchema .Shortcode
44
+ " custom" -> ReactionSchema .Custom
45
+ else -> ReactionSchema .Unknown
46
+ }
47
+ }
48
+
49
+ private fun getReactionAction (action : String ): ReactionAction {
50
+ return when (action) {
51
+ " removed" -> ReactionAction .Removed
52
+ " added" -> ReactionAction .Added
53
+ else -> ReactionAction .Unknown
54
+ }
26
55
}
27
56
28
57
data class ReactionCodec (override var contentType : ContentTypeId = ContentTypeReaction ) :
29
58
ContentCodec <Reaction > {
30
59
31
60
override fun encode (content : Reaction ): EncodedContent {
32
- val gson = GsonBuilder ().create()
61
+ val gson = GsonBuilder ()
62
+ .registerTypeAdapter(Reaction ::class .java, ReactionSerializer ())
63
+ .create()
64
+
33
65
return EncodedContent .newBuilder().also {
34
66
it.type = ContentTypeReaction
35
67
it.content = gson.toJson(content).toByteStringUtf8()
36
68
}.build()
37
69
}
38
70
39
71
override fun decode (content : EncodedContent ): Reaction {
40
- val text = content.content.toStringUtf8()
72
+ val json = content.content.toStringUtf8()
41
73
42
- // First try to decode it in the canonical form.
74
+ val gson = GsonBuilder ()
75
+ .registerTypeAdapter(Reaction ::class .java, ReactionDeserializer ())
76
+ .create()
43
77
try {
44
- return GsonBuilder ().create(). fromJson(text , Reaction ::class .java)
78
+ return gson. fromJson(json , Reaction ::class .java)
45
79
} catch (ignore: Exception ) {
46
80
}
47
81
48
82
// If that fails, try to decode it in the legacy form.
49
83
return Reaction (
50
84
reference = content.parametersMap[" reference" ] ? : " " ,
51
- action = content.parametersMap[" action" ]?.let { ReactionAction .valueOf(it) } !! ,
52
- schema = content.parametersMap[" schema" ]?.let { ReactionSchema .valueOf(it) } !! ,
53
- content = text ,
85
+ action = getReactionAction( content.parametersMap[" action" ]?.lowercase() ? : " " ) ,
86
+ schema = getReactionSchema( content.parametersMap[" schema" ]?.lowercase() ? : " " ) ,
87
+ content = json ,
54
88
)
55
89
}
56
90
57
91
override fun fallback (content : Reaction ): String? {
58
92
return when (content.action) {
59
- ReactionAction .added -> " Reacted “${content.content} ” to an earlier message"
60
- ReactionAction .removed -> " Removed “${content.content} ” from an earlier message"
93
+ ReactionAction .Added -> " Reacted “${content.content} ” to an earlier message"
94
+ ReactionAction .Removed -> " Removed “${content.content} ” from an earlier message"
95
+ else -> null
61
96
}
62
97
}
63
98
}
99
+
100
+ private class ReactionSerializer : JsonSerializer <Reaction > {
101
+ override fun serialize (
102
+ src : Reaction ,
103
+ typeOfSrc : Type ,
104
+ context : JsonSerializationContext ,
105
+ ): JsonObject {
106
+ val json = JsonObject ()
107
+ json.addProperty(" reference" , src.reference)
108
+ json.addProperty(" action" , src.action.javaClass.simpleName.lowercase())
109
+ json.addProperty(" content" , src.content)
110
+ json.addProperty(" schema" , src.schema.javaClass.simpleName.lowercase())
111
+ return json
112
+ }
113
+ }
114
+
115
+ private class ReactionDeserializer : JsonDeserializer <Reaction > {
116
+ override fun deserialize (
117
+ json : JsonElement ,
118
+ typeOfT : Type ? ,
119
+ context : JsonDeserializationContext ? ,
120
+ ): Reaction {
121
+ val jsonObject = json.asJsonObject
122
+ val reference = jsonObject.get(" reference" ).asString
123
+ val actionStr = jsonObject.get(" action" ).asString.lowercase()
124
+ val content = jsonObject.get(" content" ).asString
125
+ val schemaStr = jsonObject.get(" schema" ).asString.lowercase()
126
+
127
+ val action = getReactionAction(actionStr)
128
+ val schema = getReactionSchema(schemaStr)
129
+
130
+ return Reaction (reference, action, content, schema)
131
+ }
132
+ }
0 commit comments