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

org.http4k.client.internal.internal.kt Maven / Gradle / Ivy

The newest version!
package org.http4k.client.internal

import org.http4k.core.Headers
import org.http4k.core.Uri
import org.http4k.websocket.PushPullAdaptingWebSocket
import org.http4k.websocket.WsClient
import org.http4k.websocket.WsConsumer
import org.http4k.websocket.WsMessage
import org.http4k.websocket.WsStatus
import org.java_websocket.client.WebSocketClient
import org.java_websocket.drafts.Draft
import org.java_websocket.handshake.ServerHandshake
import java.net.URI
import java.nio.ByteBuffer
import java.time.Duration
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.atomic.AtomicReference

internal class AdaptingWebSocket(
    private val client: WebSocketClient,
    private val autoReconnection: Boolean
) : PushPullAdaptingWebSocket() {
    override fun send(message: WsMessage) {
        if (autoReconnection && (client.isClosing || client.isClosed)) {
            client.closeBlocking() // ensure it's closed
            client.reconnectBlocking()
        }
        when (message.mode) {
            WsMessage.Mode.Binary -> client.send(message.body.payload)
            WsMessage.Mode.Text -> client.send(message.bodyString())
        }
    }

    override fun close(status: WsStatus) = client.close(status.code, status.description)
}

internal class BlockingQueueClient(
    uri: Uri,
    headers: Headers,
    timeout: Duration,
    draft: Draft,
    private val queue: LinkedBlockingQueue<() -> WsMessage?>
) : WebSocketClient(URI.create(uri.toString()), draft, headers.combineToMap(), timeout.toMillis().toInt()) {
    override fun onOpen(sh: ServerHandshake) {}

    override fun onClose(code: Int, reason: String?, remote: Boolean) {
        queue += { null }
    }

    override fun onMessage(message: String) {
        queue += { WsMessage(message) }
    }

    override fun onMessage(bytes: ByteBuffer) {
        queue += { WsMessage(bytes) }
    }

    override fun onError(e: Exception): Unit = throw e
}

internal fun nonBlockingClient(
    uri: Uri,
    headers: Headers,
    timeout: Duration,
    onConnect: WsConsumer,
    draft: Draft,
    socket: AtomicReference,
) = object: WebSocketClient(URI.create(uri.toString()), draft, headers.combineToMap(), timeout.toMillis().toInt()) {
    override fun onOpen(handshakedata: ServerHandshake?) = onConnect(socket.get())

    override fun onClose(code: Int, reason: String, remote: Boolean) = socket.get().triggerClose(WsStatus(code, reason))

    override fun onMessage(message: String) = socket.get().triggerMessage(WsMessage(message))

    override fun onMessage(bytes: ByteBuffer) = socket.get().triggerMessage(WsMessage(bytes))

    override fun onError(e: Exception) = socket.get().triggerError(e)
}

internal fun blockingWsClient(
    queue: LinkedBlockingQueue<() -> WsMessage?>,
    client: BlockingQueueClient,
    autoReconnection: Boolean
) = object:  WsClient {
    override fun received() = generateSequence { queue.take()() }

    override fun close(status: WsStatus) = client.close(status.code, status.description)

    override fun send(message: WsMessage) {
        if (autoReconnection && (client.isClosing || client.isClosed)) {
            client.closeBlocking() // ensure it's closed
            client.reconnectBlocking()
        }

        return when (message.mode) {
            WsMessage.Mode.Binary -> client.send(message.body.payload)
            WsMessage.Mode.Text -> client.send(message.bodyString())
        }
    }
}

private fun Headers.combineToMap() = groupBy { it.first }.mapValues { it.value.map { it.second }.joinToString(", ") }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy