All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.net.folivo.trixnity.clientserverapi.model.sync.SyncResponseSerializer.kt Maven / Gradle / Ivy

There is a newer version: 4.7.1
Show newest version
package net.folivo.trixnity.clientserverapi.model.sync

import kotlinx.serialization.json.*

// TODO maybe this could be solved completely with contextual serializers
object SyncResponseSerializer : JsonTransformingSerializer(Sync.Response.serializer()) {
    override fun transformDeserialize(element: JsonElement): JsonElement {
        require(element is JsonObject)
        val rooms = element["rooms"] ?: return element
        require(rooms is JsonObject)
        val roomsWithEventIds = JsonObject(buildMap {
            putAll(rooms)
            putAndConvertEventMap("join", rooms["join"], setOf("timeline", "state", "ephemeral", "account_data"))
            putAndConvertEventMap("leave", rooms["leave"], setOf("timeline", "state", "account_data"))
            putAndConvertEventMap("knock", rooms["knock"], setOf("knock_state"))
            putAndConvertEventMap("invite", rooms["invite"], setOf("invite_state"))
        })
        return JsonObject(buildMap {
            putAll(element)
            put("rooms", roomsWithEventIds)
        })
    }

    private fun MutableMap.putAndConvertEventMap(
        key: String,
        source: JsonElement?,
        eventContainerKeys: Set
    ) {
        if (source != null) {
            require(source is JsonObject)
            put(key, convertEventMap(source, eventContainerKeys))
        }
    }

    private fun convertEventMap(source: JsonObject, eventContainerKeys: Set): JsonObject {
        return JsonObject(buildMap {
            source.forEach {
                val roomId = it.key
                val room = it.value
                require(room is JsonObject)
                put(roomId, JsonObject(buildMap {
                    putAll(room)
                    eventContainerKeys.forEach { eventContainerKey ->
                        putAndConvertEventMapContent(eventContainerKey, room[eventContainerKey], roomId)
                    }
                }))
            }
        })
    }

    private fun MutableMap.putAndConvertEventMapContent(
        key: String,
        source: JsonElement?,
        roomId: String,
    ) {
        if (source != null) {
            require(source is JsonObject)
            val events = source["events"]
            if (events != null) {
                require(events is JsonArray)
                put(key, JsonObject(buildMap {
                    putAll(source)
                    put("events", addRoomIdToEvents(events, roomId))
                }))
            }
        }
    }

    private fun addRoomIdToEvents(source: JsonArray, roomId: String): JsonArray {
        return JsonArray(source.map { addRoomIdToEvent(it.jsonObject, roomId) })
    }

    private fun addRoomIdToEvent(event: JsonObject, roomId: String): JsonObject {
        return JsonObject(buildMap {
            putAll(event)
            put("room_id", JsonPrimitive(roomId))
            val unsigned = event["unsigned"]?.jsonObject
            if (unsigned != null) {
                val aggregations = unsigned["m.relations"]?.jsonObject
                val newAggregations =
                    if (aggregations != null) {
                        val thread = aggregations["m.thread"]?.jsonObject
                        if (thread != null) {
                            val latestEvent = thread["latest_event"]?.jsonObject
                            if (latestEvent != null) {
                                JsonObject(buildMap {
                                    putAll(aggregations)
                                    put("m.thread", JsonObject(buildMap {
                                        putAll(thread)
                                        put("latest_event", addRoomIdToEvent(latestEvent, roomId))
                                    }))
                                })
                            } else null
                        } else null
                    } else null
                val redactedBecause = unsigned["redacted_because"]?.jsonObject
                val newRedactedBecause =
                    if (redactedBecause != null) {
                        addRoomIdToEvent(redactedBecause, roomId)
                    } else null
                put("unsigned", JsonObject(buildMap {
                    putAll(unsigned)
                    if (newAggregations != null) {
                        put("m.relations", newAggregations)
                    }
                    if (newRedactedBecause != null) {
                        put("redacted_because", newRedactedBecause)
                    }
                }))
            }
        })
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy