CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor-client-core-iosx64

Ktor HTTP client core library - asynchronous framework for creating HTTP clients in Kotlin multiplatform

Pending
Overview
Eval results
Files

websocket-support.mddocs/

WebSocket Support

Full-duplex WebSocket communication with extensions support, content conversion, and platform-specific optimizations for real-time applications.

Capabilities

WebSockets Plugin

Core WebSocket plugin providing client-side WebSocket functionality.

/**
 * WebSocket client plugin for full-duplex communication
 */
object WebSockets : HttpClientPlugin<WebSockets.Config, WebSockets> {
    override val key: AttributeKey<WebSockets> = AttributeKey("WebSocket")
    
    /**
     * WebSocket configuration
     */
    class Config {
        /** Ping interval in milliseconds (-1 to disable) */
        var pingInterval: Long = -1L
        
        /** Maximum frame size in bytes */
        var maxFrameSize: Long = Long.MAX_VALUE
        
        /** Content converter for serialization */
        var contentConverter: WebsocketContentConverter? = null
        
        /**
         * Configure WebSocket extensions
         */
        fun extensions(block: WebSocketExtensionsConfig.() -> Unit)
    }
}

WebSocket Connection Functions

Functions for establishing WebSocket connections with various configuration options.

/**
 * Create WebSocket session with request configuration
 */
suspend fun HttpClient.webSocketSession(
    block: HttpRequestBuilder.() -> Unit
): DefaultClientWebSocketSession

/**
 * Create WebSocket session with URL components
 */
suspend fun HttpClient.webSocketSession(
    method: HttpMethod = HttpMethod.Get,
    host: String = "localhost",
    port: Int = DEFAULT_PORT,
    path: String = "/",
    block: HttpRequestBuilder.() -> Unit = {}
): DefaultClientWebSocketSession

/**
 * Create WebSocket session with URL string
 */
suspend fun HttpClient.webSocketSession(
    urlString: String,
    block: HttpRequestBuilder.() -> Unit = {}
): DefaultClientWebSocketSession

/**
 * Use WebSocket with session handler
 */
suspend fun HttpClient.webSocket(
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

/**
 * Use WebSocket with URL and session handler
 */
suspend fun HttpClient.webSocket(
    urlString: String,
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

/**
 * Use WebSocket with URL components
 */
suspend fun HttpClient.webSocket(
    method: HttpMethod = HttpMethod.Get,
    host: String = "localhost", 
    port: Int = DEFAULT_PORT,
    path: String = "/",
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

Usage Examples:

import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*

val client = HttpClient {
    install(WebSockets) {
        pingInterval = 20_000 // 20 seconds
        maxFrameSize = 1024 * 1024 // 1MB
    }
}

// Simple WebSocket usage
client.webSocket("wss://echo.websocket.org") {
    send("Hello WebSocket!")
    
    for (frame in incoming) {
        when (frame) {
            is Frame.Text -> {
                val message = frame.readText()
                println("Received: $message")
            }
            is Frame.Binary -> {
                val data = frame.readBytes()
                println("Received ${data.size} bytes")
            }
            is Frame.Close -> {
                println("Connection closed")
                break
            }
            else -> {}
        }
    }
}

// WebSocket session for manual control
val session = client.webSocketSession("wss://api.example.com/ws") {
    headers["Authorization"] = "Bearer $token"
}

try {
    session.send("Hello")
    val frame = session.incoming.receive()
    // Process frame
} finally {
    session.close()
}

WebSocket Session Interface

Interface for WebSocket communication sessions with frame handling.

/**
 * Default client WebSocket session implementation
 */
interface DefaultClientWebSocketSession : ClientWebSocketSession {
    /** Incoming frames channel */
    val incoming: ReceiveChannel<Frame>
    
    /** Outgoing frames channel */
    val outgoing: SendChannel<Frame>
    
    /** WebSocket extensions */
    val extensions: List<WebSocketExtension<*>>
    
    /**
     * Send text frame
     */
    suspend fun send(content: String)
    
    /**
     * Send binary frame
     */
    suspend fun send(content: ByteArray)
    
    /**
     * Send frame
     */
    suspend fun send(frame: Frame)
    
    /**
     * Close WebSocket connection
     */
    suspend fun close(reason: CloseReason = CloseReason(CloseReason.Codes.NORMAL, ""))
    
    /**
     * Flush outgoing frames
     */
    fun flush()
}

Usage Examples:

client.webSocket("wss://api.example.com/chat") {
    // Send different types of content
    send("Hello, World!") // Text frame
    send(byteArrayOf(1, 2, 3, 4)) // Binary frame
    send(Frame.Text("Custom text frame"))
    send(Frame.Binary(true, byteArrayOf(5, 6, 7, 8)))
    
    // Handle different frame types
    for (frame in incoming) {
        when (frame) {
            is Frame.Text -> {
                val text = frame.readText()
                println("Text: $text")
                
                // Echo back
                send("Echo: $text")
            }
            is Frame.Binary -> {
                val bytes = frame.readBytes()
                println("Binary data: ${bytes.size} bytes")
            }
            is Frame.Ping -> {
                println("Ping received")
                // Pong is sent automatically
            }
            is Frame.Pong -> {
                println("Pong received")
            }
            is Frame.Close -> {
                val reason = frame.readReason()
                println("Connection closed: ${reason?.message}")
                break
            }
        }
    }
}

WebSocket Capabilities

Engine capabilities for WebSocket support and extensions.

/**
 * Basic WebSocket support capability
 */
object WebSocketCapability : HttpClientEngineCapability<Unit>

/**
 * WebSocket extensions support capability
 */
object WebSocketExtensionsCapability : HttpClientEngineCapability<List<WebSocketExtensionConfig>>

Usage Examples:

val client = HttpClient(CIO)

// Check WebSocket support
if (client.isSupported(WebSocketCapability)) {
    println("WebSocket is supported by this engine")
    
    // Use WebSocket functionality
    client.webSocket("wss://api.example.com/ws") {
        // WebSocket logic
    }
} else {
    println("WebSocket not supported")
}

// Check extensions support
if (client.isSupported(WebSocketExtensionsCapability)) {
    println("WebSocket extensions are supported")
}

Short Aliases

Convenient short aliases for WebSocket functions.

/**
 * Short alias for webSocket function
 */
suspend fun HttpClient.ws(
    urlString: String,
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
) = webSocket(urlString, request, block)

/**
 * Secure WebSocket connection (wss://)
 */
suspend fun HttpClient.wss(
    host: String,
    port: Int = 443,
    path: String = "/",
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
) = webSocket(HttpMethod.Get, host, port, path, request, block)

Usage Examples:

// Short alias
client.ws("wss://echo.websocket.org") {
    send("Hello from ws!")
    val response = (incoming.receive() as Frame.Text).readText()
    println("Received: $response")
}

// Secure WebSocket with components
client.wss("api.example.com", 443, "/websocket") {
    headers["Authorization"] = "Bearer $token"
} {
    send("Authenticated message")
    // Handle frames
}

Content Conversion

Support for automatic serialization/deserialization of WebSocket messages.

/**
 * WebSocket content converter interface
 */
interface WebsocketContentConverter {
    /**
     * Serialize object to WebSocket frame
     */
    suspend fun serialize(
        charset: Charset,
        typeInfo: TypeInfo,
        value: Any
    ): Frame
    
    /**
     * Deserialize WebSocket frame to object
     */
    suspend fun deserialize(
        charset: Charset,
        typeInfo: TypeInfo,
        content: Frame
    ): Any?
}

/**
 * Send typed object (requires content converter)
 */
suspend inline fun <reified T> DefaultClientWebSocketSession.sendSerialized(data: T)

/**
 * Receive typed object (requires content converter)
 */
suspend inline fun <reified T> DefaultClientWebSocketSession.receiveDeserialized(): T

Usage Examples:

import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.Serializable

@Serializable
data class ChatMessage(val user: String, val message: String, val timestamp: Long)

val client = HttpClient {
    install(WebSockets) {
        contentConverter = KotlinxWebsocketSerializationConverter(Json)
    }
}

client.webSocket("wss://chat.example.com/room/123") {
    // Send typed object
    val message = ChatMessage("alice", "Hello everyone!", System.currentTimeMillis())
    sendSerialized(message)
    
    // Receive typed object
    val receivedMessage: ChatMessage = receiveDeserialized()
    println("${receivedMessage.user}: ${receivedMessage.message}")
}

Error Handling

WebSocket-specific exception handling and error patterns.

/**
 * Base WebSocket exception class
 */
open class WebSocketException(message: String) : IllegalStateException(message)

/**
 * WebSocket connection failed exception
 */
class WebSocketConnectionException(message: String, cause: Throwable? = null) 
    : WebSocketException(message)

/**
 * WebSocket close codes and reasons
 */
object CloseReason {
    object Codes {
        const val NORMAL = 1000
        const val GOING_AWAY = 1001
        const val PROTOCOL_ERROR = 1002
        const val UNSUPPORTED_DATA = 1003
        const val NO_STATUS = 1005
        const val ABNORMAL_CLOSURE = 1006
        const val INVALID_PAYLOAD = 1007
        const val POLICY_VIOLATION = 1008
        const val MESSAGE_TOO_BIG = 1009
        const val MANDATORY_EXTENSION = 1010
        const val INTERNAL_ERROR = 1011
        const val TLS_HANDSHAKE_FAILED = 1015
    }
}

data class CloseReason(val code: Short, val message: String)

Usage Examples:

try {
    client.webSocket("wss://api.example.com/ws") {
        send("Hello")
        
        for (frame in incoming) {
            when (frame) {
                is Frame.Close -> {
                    val reason = frame.readReason()
                    when (reason?.code) {
                        CloseReason.Codes.NORMAL -> println("Normal close")
                        CloseReason.Codes.GOING_AWAY -> println("Server going away")
                        CloseReason.Codes.PROTOCOL_ERROR -> println("Protocol error")
                        else -> println("Close reason: ${reason?.message}")
                    }
                    break
                }
                // Handle other frames
                else -> {}
            }
        }
    }
} catch (e: WebSocketException) {
    println("WebSocket error: ${e.message}")
} catch (e: WebSocketConnectionException) {
    println("Connection failed: ${e.message}")
}

// Graceful close
client.webSocket("wss://api.example.com/ws") {
    try {
        // WebSocket communication
        send("Hello")
    } finally {
        // Always close cleanly
        close(CloseReason(CloseReason.Codes.NORMAL, "Client disconnecting"))
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-ktor--ktor-client-core-iosx64

docs

client-configuration.md

cookie-management.md

engine-configuration.md

form-handling.md

http-caching.md

index.md

plugin-system.md

request-building.md

response-handling.md

websocket-support.md

tile.json