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

commonMain.io.rsocket.kotlin.internal.RSocketResponder.kt Maven / Gradle / Ivy

/*
 * Copyright 2015-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.rsocket.kotlin.internal

import io.rsocket.kotlin.*
import io.rsocket.kotlin.frame.*
import io.rsocket.kotlin.internal.flow.*
import kotlinx.coroutines.*

internal class RSocketResponder(
    private val state: RSocketState,
    private val requestHandler: RSocket,
) {

    fun handleMetadataPush(frame: MetadataPushFrame) {
        state.launch {
            requestHandler.metadataPush(frame.metadata)
        }.invokeOnCompletion {
            frame.release()
        }
    }

    fun handleFireAndForget(frame: RequestFrame) {
        state.launch {
            requestHandler.fireAndForget(frame.payload)
        }.invokeOnCompletion {
            frame.release()
        }
    }

    fun handlerRequestResponse(frame: RequestFrame): Unit = with(state) {
        val streamId = frame.streamId
        launchCancelable(streamId) {
            val response = requestOrCancel(streamId) {
                requestHandler.requestResponse(frame.payload)
            } ?: return@launchCancelable
            if (isActive) send(NextCompletePayloadFrame(streamId, response))
        }.invokeOnCompletion {
            frame.release()
        }
    }

    fun handleRequestStream(initFrame: RequestFrame): Unit = with(state) {
        val streamId = initFrame.streamId
        launchCancelable(streamId) {
            val response = requestOrCancel(streamId) {
                requestHandler.requestStream(initFrame.payload)
            } ?: return@launchCancelable
            response.collectLimiting(streamId, initFrame.initialRequest)
        }.invokeOnCompletion {
            initFrame.release()
        }
    }

    fun handleRequestChannel(initFrame: RequestFrame): Unit = with(state) {
        val streamId = initFrame.streamId
        val receiver = createReceiverFor(streamId)

        val request = RequestChannelResponderFlow(streamId, receiver, state)

        launchCancelable(streamId) {
            val response = requestOrCancel(streamId) {
                requestHandler.requestChannel(initFrame.payload, request)
            } ?: return@launchCancelable
            response.collectLimiting(streamId, initFrame.initialRequest)
        }.invokeOnCompletion {
            initFrame.release()
            if (it != null) receiver.cancelConsumed(it) //TODO check it
        }
    }

    private inline fun  CoroutineScope.requestOrCancel(streamId: Int, block: () -> T): T? =
        try {
            block()
        } catch (e: Throwable) {
            if (isActive) {
                state.send(ErrorFrame(streamId, e))
                cancel("Request handling failed", e) //KLUDGE: can be related to IR, because using `throw` fails on JS IR and Native
            }
            null
        }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy