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

commonMain.io.github.xlopec.tea.time.travel.session.DebugWebSocketSession.kt Maven / Gradle / Ivy

/*
 * MIT License
 *
 * Copyright (c) 2022. Maksym Oliinyk.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package io.github.xlopec.tea.time.travel.session

import arrow.core.Either
import io.github.xlopec.tea.time.travel.component.Settings
import io.github.xlopec.tea.time.travel.protocol.*
import io.ktor.websocket.*
import kotlinx.coroutines.flow.*
import kotlin.reflect.KClass

@PublishedApi
internal class DebugWebSocketSession(
    private val mClass: KClass,
    private val sClass: KClass,
    private val settings: Settings,
    socketSession: WebSocketSession
) : DebugSession, WebSocketSession by socketSession {

    private val incomingPackets: Flow> = incomingCommands(settings)

    override val messages: Flow = incomingPackets.messages()
    override val states: Flow = incomingPackets.states()

    override suspend fun invoke(packet: NotifyServer) =
        send(settings.serializer.toJson(packet))

    private fun WebSocketSession.incomingCommands(
        settings: Settings
    ) = incomingPackets(settings)
        .map { packet -> settings.serializer.toCommand(packet) }

    private fun JsonSerializer.toCommand(
        packet: NotifyClient
    ) = when (val message = packet.message) {
        is ApplyMessage -> Either.Left(fromJsonTree(message.message, mClass))
        is ApplyState -> Either.Right(fromJsonTree(message.state, sClass))
    }
}

private fun  Flow>.states(): Flow =
    filterIsInstance>().map { (s) -> s }

private fun  Flow>.messages(): Flow =
    filterIsInstance>().map { (m) -> m }

private fun  WebSocketSession.incomingPackets(
    settings: Settings
): Flow> =
    incoming.receiveAsFlow().shareIn(this, SharingStarted.Lazily)
        .filterIsInstance()
        .map { frame -> frame.readText() }
        .map { json -> settings.serializer.asNotifyClientPacket(json) }
        .filter { packet -> packet.component == settings.id }

@Suppress("UNCHECKED_CAST")
private fun  JsonSerializer.asNotifyClientPacket(
    json: String
) = fromJson(json, NotifyClient::class) as NotifyClient