CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/gradle-io-ktor--ktor-client-websockets-mingwx64

WebSocket client support for Ktor targeting the MinGW x64 platform, enabling native Windows applications built with Kotlin/Native to establish WebSocket connections.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

Ktor Client WebSockets (mingwx64)

Ktor WebSocket client plugin for MinGW x64 platform, enabling native Windows applications built with Kotlin/Native to establish WebSocket connections. This plugin provides complete WebSocket client functionality including bidirectional communication, message serialization, connection lifecycle management, and ping/pong support for connection health monitoring.

Package Information

  • Package Name: ktor-client-websockets-mingwx64
  • Package Type: gradle
  • Language: Kotlin
  • Target Platform: mingwx64 (Native Windows)
  • Installation: implementation("io.ktor:ktor-client-websockets-mingwx64:3.2.0")

Core Imports

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

For WebSocket frames and session types:

import io.ktor.websocket.*

For serialization support:

import io.ktor.websocket.serialization.*

Basic Usage

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

// Create client with WebSocket plugin
val client = HttpClient(WinHttp) {
    install(WebSockets) {
        pingInterval = 30.seconds
        maxFrameSize = 1024 * 1024 // 1MB
    }
}

// Connect and use WebSocket
client.webSocket(
    method = HttpMethod.Get,
    host = "echo.websocket.org",
    port = 80,
    path = "/"
) {
    // Send text message
    send(Frame.Text("Hello WebSocket!"))
    
    // Receive message
    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 binary data: ${data.size} bytes")
            }
            is Frame.Close -> {
                println("Connection closed")
                break
            }
            else -> {}
        }
    }
}

client.close()

Architecture

The Ktor WebSocket client plugin integrates with the Ktor HTTP client framework through several key components:

  • WebSockets Plugin: Core plugin that handles WebSocket upgrade negotiations and session management
  • ClientWebSocketSession: Client-specific session interface providing access to the underlying HTTP call
  • DefaultClientWebSocketSession: Default session implementation with ping/pong support and content serialization
  • Connection Builders: Extension functions for establishing WebSocket connections with various configuration options
  • Content Serialization: Optional converter for automatic serialization/deserialization of custom types
  • Extensions Support: Mechanism for WebSocket protocol extensions (deflate compression, etc.)

Capabilities

Plugin Installation and Configuration

Install and configure the WebSocket plugin for your HttpClient instance.

fun HttpClientConfig<*>.WebSockets(config: WebSockets.Config.() -> Unit)

class WebSockets {
    constructor()
    constructor(pingIntervalMillis: Long, maxFrameSize: Long)
    constructor(
        pingIntervalMillis: Long,
        maxFrameSize: Long,
        extensionsConfig: WebSocketExtensionsConfig,
        contentConverter: WebsocketContentConverter? = null
    )
    
    val pingIntervalMillis: Long
    val maxFrameSize: Long
    val contentConverter: WebsocketContentConverter?
}

fun WebSockets(
    pingInterval: Duration?,
    maxFrameSize: Long = Int.MAX_VALUE.toLong()
): WebSockets

class WebSockets.Config {
    var pingIntervalMillis: Long
    var maxFrameSize: Long
    var pingInterval: Duration?
    var contentConverter: WebsocketContentConverter?
    
    fun extensions(block: WebSocketExtensionsConfig.() -> Unit)
}

WebSocket Connection Establishment

Create WebSocket connections using various methods - session-based for manual management or block-based for automatic cleanup.

suspend fun HttpClient.webSocketSession(
    block: HttpRequestBuilder.() -> Unit
): DefaultClientWebSocketSession

suspend fun HttpClient.webSocketSession(
    method: HttpMethod = HttpMethod.Get,
    host: String? = null,
    port: Int? = null,
    path: String? = null,
    block: HttpRequestBuilder.() -> Unit = {}
): DefaultClientWebSocketSession

suspend fun HttpClient.webSocketSession(
    urlString: String,
    block: HttpRequestBuilder.() -> Unit = {}
): DefaultClientWebSocketSession

suspend fun HttpClient.webSocket(
    request: HttpRequestBuilder.() -> Unit,
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

suspend fun HttpClient.webSocket(
    method: HttpMethod = HttpMethod.Get,
    host: String? = null,
    port: Int? = null,
    path: String? = null,
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

suspend fun HttpClient.webSocket(
    urlString: String,
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

Secure WebSocket Connections

Establish secure WebSocket connections over SSL/TLS using the WSS protocol.

suspend fun HttpClient.wss(
    request: HttpRequestBuilder.() -> Unit,
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

suspend fun HttpClient.wss(
    method: HttpMethod = HttpMethod.Get,
    host: String? = null,
    port: Int? = null,
    path: String? = null,
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

suspend fun HttpClient.wss(
    urlString: String,
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

Convenience Connection Functions

Shorthand functions for WebSocket connections - ws aliases for standard connections.

suspend fun HttpClient.ws(
    method: HttpMethod = HttpMethod.Get,
    host: String? = null,
    port: Int? = null,
    path: String? = null,
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

suspend fun HttpClient.ws(
    request: HttpRequestBuilder.() -> Unit,
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

suspend fun HttpClient.ws(
    urlString: String,
    request: HttpRequestBuilder.() -> Unit = {},
    block: suspend DefaultClientWebSocketSession.() -> Unit
)

Session Management

Client-specific WebSocket session interfaces providing access to the underlying HTTP call and session management.

interface ClientWebSocketSession : WebSocketSession {
    val call: HttpClientCall
}

open class DefaultClientWebSocketSession(
    override val call: HttpClientCall,
    delegate: DefaultWebSocketSession
) : ClientWebSocketSession, DefaultWebSocketSession

val DefaultClientWebSocketSession.converter: WebsocketContentConverter?

Message Serialization

Automatic serialization and deserialization of custom types using configured content converters.

suspend fun DefaultClientWebSocketSession.sendSerialized(
    data: Any?,
    typeInfo: TypeInfo
)

suspend inline fun <reified T> DefaultClientWebSocketSession.sendSerialized(
    data: T
)

suspend fun <T> DefaultClientWebSocketSession.receiveDeserialized(
    typeInfo: TypeInfo
): T

suspend inline fun <reified T> DefaultClientWebSocketSession.receiveDeserialized(): T

interface WebsocketContentConverter {
    suspend fun serialize(
        charset: Charset,
        typeInfo: TypeInfo,
        value: Any?
    ): Frame
    
    suspend fun deserialize(
        charset: Charset,
        typeInfo: TypeInfo,
        content: Frame
    ): Any?
    
    fun isApplicable(frame: Frame): Boolean
}

suspend inline fun <reified T> WebsocketContentConverter.serialize(
    value: T,
    charset: Charset = Charsets.UTF_8
): Frame

suspend inline fun <reified T> WebsocketContentConverter.deserialize(
    content: Frame,
    charset: Charset = Charsets.UTF_8
): T

Engine Capabilities

Capability indicators for WebSocket support in HTTP client engines.

object WebSocketCapability : HttpClientEngineCapability<Unit>

object WebSocketExtensionsCapability : HttpClientEngineCapability<Unit>

Exception Handling

WebSocket-specific exception types for error handling.

class WebSocketException(message: String, cause: Throwable?) : IllegalStateException {
    constructor(message: String)
}

open class WebsocketContentConvertException(
    message: String,
    cause: Throwable? = null
) : ContentConvertException

class WebsocketConverterNotFoundException(
    message: String,
    cause: Throwable? = null
) : WebsocketContentConvertException

class WebsocketDeserializeException(
    message: String,
    cause: Throwable? = null,
    val frame: Frame
) : WebsocketContentConvertException

Constants

Important constants used in WebSocket configuration.

const val PINGER_DISABLED: Long = 0

Core WebSocket Types

WebSocket Session Interface

Base WebSocket session interface from the shared websocket module.

interface WebSocketSession : CoroutineScope {
    var masking: Boolean
    var maxFrameSize: Long
    val incoming: ReceiveChannel<Frame>
    val outgoing: SendChannel<Frame>
    val extensions: List<WebSocketExtension<*>>
    
    suspend fun send(frame: Frame)
    suspend fun flush()
}

class DefaultWebSocketSession : WebSocketSession

WebSocket Frames

Frame types for different kinds of WebSocket messages.

sealed class Frame {
    class Text(val data: ByteArray) : Frame {
        constructor(text: String)
        fun readText(): String
    }
    
    class Binary(val data: ByteArray) : Frame {
        fun readBytes(): ByteArray
    }
    
    class Close(val data: ByteArray) : Frame {
        constructor(reason: CloseReason?)
        fun readReason(): CloseReason?
    }
    
    class Ping(val data: ByteArray) : Frame {
        constructor()
    }
    
    class Pong(val data: ByteArray) : Frame {
        constructor()
    }
}

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

WebSocket Extensions

Extension mechanism for WebSocket protocol extensions.

interface WebSocketExtension<ConfigType : Any> {
    val factory: WebSocketExtensionFactory<ConfigType, out WebSocketExtension<ConfigType>>
    val protocols: List<WebSocketExtensionHeader>
    
    fun clientNegotiation(negotiatedProtocols: List<WebSocketExtensionHeader>): Boolean
    fun serverNegotiation(requestedProtocols: List<WebSocketExtensionHeader>): List<WebSocketExtensionHeader>
    fun processOutgoingFrame(frame: Frame): Frame
    fun processIncomingFrame(frame: Frame): Frame
}

interface WebSocketExtensionFactory<ConfigType : Any, ExtensionType : WebSocketExtension<ConfigType>> {
    val key: AttributeKey<ExtensionType>
    val rsv1: Boolean
    val rsv2: Boolean
    val rsv3: Boolean
    
    fun install(config: ConfigType.() -> Unit): ExtensionType
}

class WebSocketExtensionsConfig {
    fun <ConfigType : Any> install(
        extension: WebSocketExtensionFactory<ConfigType, *>,
        config: ConfigType.() -> Unit = {}
    )
    
    fun build(): List<WebSocketExtension<*>>
}

Usage Examples

Basic Text Messaging

client.webSocket("wss://echo.websocket.org") {
    // Send text message
    send(Frame.Text("Hello WebSocket!"))
    
    // Read response
    val response = incoming.receive()
    if (response is Frame.Text) {
        println("Echo: ${response.readText()}")
    }
}

Binary Data Transfer

client.webSocket(host = "example.com", port = 8080, path = "/websocket") {
    // Send binary data
    val binaryData = byteArrayOf(1, 2, 3, 4, 5)
    send(Frame.Binary(binaryData))
    
    // Receive binary response
    for (frame in incoming) {
        when (frame) {
            is Frame.Binary -> {
                val receivedData = frame.readBytes()
                println("Received ${receivedData.size} bytes")
            }
            is Frame.Close -> break
            else -> {}
        }
    }
}

Connection with Ping/Pong

val client = HttpClient(WinHttp) {
    install(WebSockets) {
        pingInterval = 30.seconds // Send ping every 30 seconds
        maxFrameSize = 1024 * 1024 // 1MB max frame size
    }
}

client.webSocket("wss://example.com/websocket") {
    // Ping frames are sent automatically
    // Connection will be kept alive with ping/pong
    
    for (frame in incoming) {
        when (frame) {
            is Frame.Text -> {
                println("Message: ${frame.readText()}")
            }
            is Frame.Ping -> {
                // Pong is sent automatically
                println("Ping received")
            }
            is Frame.Pong -> {
                println("Pong received")
            }
            is Frame.Close -> {
                println("Connection closed: ${frame.readReason()}")
                break
            }
            else -> {}
        }
    }
}

Serialized Object Communication

// Configure serialization
val client = HttpClient(WinHttp) {
    install(WebSockets) {
        contentConverter = KotlinxWebsocketSerializationConverter(Json)
    }
}

client.webSocket("wss://api.example.com/websocket") {
    // Send serialized object
    sendSerialized(UserMessage("Hello", "user123"))
    
    // Receive and deserialize
    val response = receiveDeserialized<ServerResponse>()
    println("Received: ${response.message}")
}

Connection Error Handling

try {
    client.webSocket("wss://unreachable.example.com") {
        send(Frame.Text("Hello"))
    }
} catch (e: WebSocketException) {
    println("WebSocket error: ${e.message}")
} catch (e: ConnectTimeoutException) {
    println("Connection timeout")
} catch (e: Exception) {
    println("General error: ${e.message}")
}

docs

index.md

tile.json