CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor-client-websockets-macosarm64

WebSocket plugin for Ktor HTTP client enabling full-duplex real-time communication

Pending
Overview
Eval results
Files

message-handling.mddocs/

Message Handling

Client-specific WebSocket session interfaces and message serialization capabilities that integrate with Ktor's HTTP client call lifecycle and provide automatic content conversion.

Capabilities

Client WebSocket Session Interface

Core interface for client-side WebSocket sessions that provides access to the associated HTTP client call.

/**
 * Client specific WebSocketSession with access to HTTP call context
 */
interface ClientWebSocketSession : WebSocketSession {
    /**
     * HttpClientCall associated with this WebSocket session
     */
    val call: HttpClientCall
}

Default Client WebSocket Session

Default implementation of client WebSocket session that delegates to DefaultWebSocketSession while providing HTTP call access.

/**
 * Default implementation of ClientWebSocketSession
 */
class DefaultClientWebSocketSession(
    override val call: HttpClientCall,
    delegate: DefaultWebSocketSession
) : ClientWebSocketSession, DefaultWebSocketSession by delegate

Usage Examples:

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

val client = HttpClient {
    install(WebSockets)
}

client.webSocket("ws://localhost:8080/websocket") { session ->
    // session is DefaultClientWebSocketSession
    
    // Access HTTP call information
    val requestUrl = session.call.request.url
    val userAgent = session.call.request.headers["User-Agent"]
    
    println("Connected to: $requestUrl")
    println("User-Agent: $userAgent")
    
    // Use standard WebSocket operations
    session.send("Hello from ${userAgent}")
    
    for (frame in session.incoming) {
        when (frame) {
            is Frame.Text -> println("Received: ${frame.readText()}")
            is Frame.Close -> break
            else -> {}
        }
    }
}

Content Converter Access

Access to the WebSocket content converter configured in the plugin for automatic serialization/deserialization.

/**
 * Extension property to access the content converter from WebSockets plugin
 */
val DefaultClientWebSocketSession.converter: WebsocketContentConverter?

Usage Examples:

client.webSocket("ws://localhost:8080/api") {
    val converter = this.converter
    if (converter != null) {
        println("Content converter available: ${converter::class.simpleName}")
    } else {
        println("No content converter configured")
    }
}

Message Serialization

Send serialized data using the configured content converter.

/**
 * Serializes data to a frame and enqueues it using TypeInfo
 */
suspend fun DefaultClientWebSocketSession.sendSerialized(
    data: Any?, 
    typeInfo: TypeInfo
)

/**
 * Serializes data to a frame and enqueues it using reified type
 */
suspend inline fun <reified T> DefaultClientWebSocketSession.sendSerialized(data: T)

Usage Examples:

import io.ktor.util.reflect.*

data class Message(val text: String, val timestamp: Long)
data class User(val id: Int, val name: String)

val client = HttpClient {
    install(WebSockets) {
        contentConverter = JsonWebsocketContentConverter()
    }
}

client.webSocket("ws://localhost:8080/chat") {
    // Send with reified type (recommended)
    sendSerialized(Message("Hello", System.currentTimeMillis()))
    
    // Send with explicit TypeInfo
    val user = User(123, "Alice")
    sendSerialized(user, typeInfo<User>())
    
    // Handle responses...
}

Message Deserialization

Receive and deserialize frames using the configured content converter.

/**
 * Dequeues a frame and deserializes it using TypeInfo
 */
suspend fun <T> DefaultClientWebSocketSession.receiveDeserialized(typeInfo: TypeInfo): T

/**
 * Dequeues a frame and deserializes it using reified type
 */
suspend inline fun <reified T> DefaultClientWebSocketSession.receiveDeserialized(): T

Usage Examples:

client.webSocket("ws://localhost:8080/api") {
    // Send a request
    sendSerialized(ApiRequest("getUserList"))
    
    // Receive typed response (recommended)
    val userList: List<User> = receiveDeserialized()
    println("Received ${userList.size} users")
    
    // Receive with explicit TypeInfo
    val response: ApiResponse = receiveDeserialized(typeInfo<ApiResponse>())
    println("API response: ${response.status}")
}

Error Handling for Serialization

Serialization and deserialization operations can throw specific exceptions.

/**
 * Base exception for WebSocket content conversion errors
 */
open class WebsocketContentConvertException(
    message: String,
    cause: Throwable? = null
) : ContentConvertException(message, cause)

/**
 * Exception thrown when no content converter is found
 */
class WebsocketConverterNotFoundException(
    message: String,
    cause: Throwable? = null
) : WebsocketContentConvertException(message, cause)

/**
 * Exception thrown when deserialization fails
 */
class WebsocketDeserializeException(
    message: String,
    cause: Throwable? = null,
    val frame: Frame
) : WebsocketContentConvertException(message, cause)

Usage Examples:

client.webSocket("ws://localhost:8080/api") {
    try {
        // This will throw if no converter is configured
        sendSerialized(MyData("test"))
        
        val response: MyResponse = receiveDeserialized()
        
    } catch (e: WebsocketConverterNotFoundException) {
        println("No content converter configured: ${e.message}")
        
    } catch (e: WebsocketDeserializeException) {
        println("Failed to deserialize message: ${e.message}")
        e.frame?.let { frame ->
            println("Problematic frame type: ${frame::class.simpleName}")
        }
        
    } catch (e: ClosedReceiveChannelException) {
        println("WebSocket connection closed")
    }
}

Raw Frame Access

Direct access to WebSocket frames alongside serialization capabilities.

Usage Examples:

client.webSocket("ws://localhost:8080/mixed") {
    // Send serialized data
    sendSerialized(MyMessage("Hello"))
    
    // Send raw frame
    send("Raw text message")
    
    // Handle mixed message types
    for (frame in incoming) {
        when (frame) {
            is Frame.Text -> {
                val text = frame.readText()
                if (text.startsWith("{")) {
                    // Assume JSON, deserialize manually
                    try {
                        val data: MyMessage = converter?.deserialize(
                            frame,
                            typeInfo<MyMessage>()
                        ) ?: error("No converter")
                        println("Structured: $data")
                    } catch (e: Exception) {
                        println("Raw text: $text")
                    }
                } else {
                    println("Raw text: $text")
                }
            }
            is Frame.Binary -> {
                // Handle binary frames
                val bytes = frame.readBytes()
                println("Binary data: ${bytes.size} bytes")
            }
            is Frame.Close -> break
            else -> {}
        }
    }
}

Session Management with HTTP Context

Leverage HTTP call context for WebSocket session management.

Usage Examples:

client.webSocket("ws://localhost:8080/websocket") {
    // Access request information
    val originalUrl = call.request.url
    val requestHeaders = call.request.headers
    
    // Access response information (from upgrade response)
    val responseStatus = call.response.status
    val responseHeaders = call.response.headers
    
    println("Upgraded from: $originalUrl")
    println("Response status: $responseStatus")
    
    // Check if specific headers were set during upgrade
    val serverProtocol = responseHeaders["Sec-WebSocket-Protocol"]
    if (serverProtocol != null) {
        println("Server selected protocol: $serverProtocol")
    }
    
    // Use this information for session logic
    send("Connected with protocol: ${serverProtocol ?: "default"}")
}

Install with Tessl CLI

npx tessl i tessl/maven-io-ktor--ktor-client-websockets-macosarm64

docs

connection-management.md

index.md

message-handling.md

plugin-configuration.md

tile.json