or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

connection-management.mdindex.mdmessage-handling.mdplugin-configuration.md

message-handling.mddocs/

0

# Message Handling

1

2

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

3

4

## Capabilities

5

6

### Client WebSocket Session Interface

7

8

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

9

10

```kotlin { .api }

11

/**

12

* Client specific WebSocketSession with access to HTTP call context

13

*/

14

interface ClientWebSocketSession : WebSocketSession {

15

/**

16

* HttpClientCall associated with this WebSocket session

17

*/

18

val call: HttpClientCall

19

}

20

```

21

22

### Default Client WebSocket Session

23

24

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

25

26

```kotlin { .api }

27

/**

28

* Default implementation of ClientWebSocketSession

29

*/

30

class DefaultClientWebSocketSession(

31

override val call: HttpClientCall,

32

delegate: DefaultWebSocketSession

33

) : ClientWebSocketSession, DefaultWebSocketSession by delegate

34

```

35

36

**Usage Examples:**

37

38

```kotlin

39

import io.ktor.client.*

40

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

41

import io.ktor.websocket.*

42

43

val client = HttpClient {

44

install(WebSockets)

45

}

46

47

client.webSocket("ws://localhost:8080/websocket") { session ->

48

// session is DefaultClientWebSocketSession

49

50

// Access HTTP call information

51

val requestUrl = session.call.request.url

52

val userAgent = session.call.request.headers["User-Agent"]

53

54

println("Connected to: $requestUrl")

55

println("User-Agent: $userAgent")

56

57

// Use standard WebSocket operations

58

session.send("Hello from ${userAgent}")

59

60

for (frame in session.incoming) {

61

when (frame) {

62

is Frame.Text -> println("Received: ${frame.readText()}")

63

is Frame.Close -> break

64

else -> {}

65

}

66

}

67

}

68

```

69

70

### Content Converter Access

71

72

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

73

74

```kotlin { .api }

75

/**

76

* Extension property to access the content converter from WebSockets plugin

77

*/

78

val DefaultClientWebSocketSession.converter: WebsocketContentConverter?

79

```

80

81

**Usage Examples:**

82

83

```kotlin

84

client.webSocket("ws://localhost:8080/api") {

85

val converter = this.converter

86

if (converter != null) {

87

println("Content converter available: ${converter::class.simpleName}")

88

} else {

89

println("No content converter configured")

90

}

91

}

92

```

93

94

### Message Serialization

95

96

Send serialized data using the configured content converter.

97

98

```kotlin { .api }

99

/**

100

* Serializes data to a frame and enqueues it using TypeInfo

101

*/

102

suspend fun DefaultClientWebSocketSession.sendSerialized(

103

data: Any?,

104

typeInfo: TypeInfo

105

)

106

107

/**

108

* Serializes data to a frame and enqueues it using reified type

109

*/

110

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

111

```

112

113

**Usage Examples:**

114

115

```kotlin

116

import io.ktor.util.reflect.*

117

118

data class Message(val text: String, val timestamp: Long)

119

data class User(val id: Int, val name: String)

120

121

val client = HttpClient {

122

install(WebSockets) {

123

contentConverter = JsonWebsocketContentConverter()

124

}

125

}

126

127

client.webSocket("ws://localhost:8080/chat") {

128

// Send with reified type (recommended)

129

sendSerialized(Message("Hello", System.currentTimeMillis()))

130

131

// Send with explicit TypeInfo

132

val user = User(123, "Alice")

133

sendSerialized(user, typeInfo<User>())

134

135

// Handle responses...

136

}

137

```

138

139

### Message Deserialization

140

141

Receive and deserialize frames using the configured content converter.

142

143

```kotlin { .api }

144

/**

145

* Dequeues a frame and deserializes it using TypeInfo

146

*/

147

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

148

149

/**

150

* Dequeues a frame and deserializes it using reified type

151

*/

152

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

153

```

154

155

**Usage Examples:**

156

157

```kotlin

158

client.webSocket("ws://localhost:8080/api") {

159

// Send a request

160

sendSerialized(ApiRequest("getUserList"))

161

162

// Receive typed response (recommended)

163

val userList: List<User> = receiveDeserialized()

164

println("Received ${userList.size} users")

165

166

// Receive with explicit TypeInfo

167

val response: ApiResponse = receiveDeserialized(typeInfo<ApiResponse>())

168

println("API response: ${response.status}")

169

}

170

```

171

172

### Error Handling for Serialization

173

174

Serialization and deserialization operations can throw specific exceptions.

175

176

```kotlin { .api }

177

/**

178

* Base exception for WebSocket content conversion errors

179

*/

180

open class WebsocketContentConvertException(

181

message: String,

182

cause: Throwable? = null

183

) : ContentConvertException(message, cause)

184

185

/**

186

* Exception thrown when no content converter is found

187

*/

188

class WebsocketConverterNotFoundException(

189

message: String,

190

cause: Throwable? = null

191

) : WebsocketContentConvertException(message, cause)

192

193

/**

194

* Exception thrown when deserialization fails

195

*/

196

class WebsocketDeserializeException(

197

message: String,

198

cause: Throwable? = null,

199

val frame: Frame

200

) : WebsocketContentConvertException(message, cause)

201

```

202

203

**Usage Examples:**

204

205

```kotlin

206

client.webSocket("ws://localhost:8080/api") {

207

try {

208

// This will throw if no converter is configured

209

sendSerialized(MyData("test"))

210

211

val response: MyResponse = receiveDeserialized()

212

213

} catch (e: WebsocketConverterNotFoundException) {

214

println("No content converter configured: ${e.message}")

215

216

} catch (e: WebsocketDeserializeException) {

217

println("Failed to deserialize message: ${e.message}")

218

e.frame?.let { frame ->

219

println("Problematic frame type: ${frame::class.simpleName}")

220

}

221

222

} catch (e: ClosedReceiveChannelException) {

223

println("WebSocket connection closed")

224

}

225

}

226

```

227

228

### Raw Frame Access

229

230

Direct access to WebSocket frames alongside serialization capabilities.

231

232

**Usage Examples:**

233

234

```kotlin

235

client.webSocket("ws://localhost:8080/mixed") {

236

// Send serialized data

237

sendSerialized(MyMessage("Hello"))

238

239

// Send raw frame

240

send("Raw text message")

241

242

// Handle mixed message types

243

for (frame in incoming) {

244

when (frame) {

245

is Frame.Text -> {

246

val text = frame.readText()

247

if (text.startsWith("{")) {

248

// Assume JSON, deserialize manually

249

try {

250

val data: MyMessage = converter?.deserialize(

251

frame,

252

typeInfo<MyMessage>()

253

) ?: error("No converter")

254

println("Structured: $data")

255

} catch (e: Exception) {

256

println("Raw text: $text")

257

}

258

} else {

259

println("Raw text: $text")

260

}

261

}

262

is Frame.Binary -> {

263

// Handle binary frames

264

val bytes = frame.readBytes()

265

println("Binary data: ${bytes.size} bytes")

266

}

267

is Frame.Close -> break

268

else -> {}

269

}

270

}

271

}

272

```

273

274

### Session Management with HTTP Context

275

276

Leverage HTTP call context for WebSocket session management.

277

278

**Usage Examples:**

279

280

```kotlin

281

client.webSocket("ws://localhost:8080/websocket") {

282

// Access request information

283

val originalUrl = call.request.url

284

val requestHeaders = call.request.headers

285

286

// Access response information (from upgrade response)

287

val responseStatus = call.response.status

288

val responseHeaders = call.response.headers

289

290

println("Upgraded from: $originalUrl")

291

println("Response status: $responseStatus")

292

293

// Check if specific headers were set during upgrade

294

val serverProtocol = responseHeaders["Sec-WebSocket-Protocol"]

295

if (serverProtocol != null) {

296

println("Server selected protocol: $serverProtocol")

297

}

298

299

// Use this information for session logic

300

send("Connected with protocol: ${serverProtocol ?: "default"}")

301

}

302

```