or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-configuration.mdcontent-handling.mdengine-architecture.mdevents-monitoring.mdhttp-statement.mdindex.mdplugin-system.mdrequest-building.mdresponse-handling.mdwebsocket-support.md

websocket-support.mddocs/

0

# WebSocket Support

1

2

Full WebSocket client implementation with session management, message handling, connection lifecycle, and support for both text and binary messaging with automatic connection management.

3

4

## Capabilities

5

6

### WebSockets Plugin

7

8

Core WebSocket plugin for HTTP client.

9

10

```kotlin { .api }

11

/**

12

* WebSocket plugin for HTTP client

13

*/

14

class WebSockets private constructor() {

15

companion object Plugin : HttpClientPlugin<Config, WebSockets> {

16

override val key: AttributeKey<WebSockets>

17

}

18

19

/**

20

* WebSocket plugin configuration

21

*/

22

class Config {

23

/** Ping interval in milliseconds */

24

var pingInterval: Long? = null

25

26

/** Connection timeout in milliseconds */

27

var timeout: Long = 15000

28

29

/** Maximum frame size */

30

var maxFrameSize: Long = Long.MAX_VALUE

31

32

/** Content converter for message serialization */

33

var contentConverter: WebsocketContentConverter? = null

34

}

35

}

36

```

37

38

### WebSocket Connection

39

40

Establish WebSocket connections with various configuration options.

41

42

```kotlin { .api }

43

/**

44

* Establish WebSocket connection

45

* @param urlString - WebSocket URL (ws:// or wss://)

46

* @param block - WebSocket session handling block

47

*/

48

suspend fun HttpClient.webSocket(

49

urlString: String,

50

block: suspend ClientWebSocketSession.() -> Unit

51

)

52

53

suspend fun HttpClient.webSocket(

54

method: HttpMethod = HttpMethod.Get,

55

host: String = "localhost",

56

port: Int = DEFAULT_PORT,

57

path: String = "/",

58

block: suspend ClientWebSocketSession.() -> Unit

59

)

60

61

suspend fun HttpClient.webSocket(

62

block: HttpRequestBuilder.() -> Unit,

63

sessionBlock: suspend ClientWebSocketSession.() -> Unit

64

)

65

66

/**

67

* Establish secure WebSocket connection (wss://)

68

*/

69

suspend fun HttpClient.wss(

70

urlString: String,

71

block: suspend ClientWebSocketSession.() -> Unit

72

)

73

74

/**

75

* Establish insecure WebSocket connection (ws://)

76

*/

77

suspend fun HttpClient.ws(

78

urlString: String,

79

block: suspend ClientWebSocketSession.() -> Unit

80

)

81

```

82

83

**Usage Examples:**

84

85

```kotlin

86

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

87

import io.ktor.websocket.*

88

89

val client = HttpClient {

90

install(WebSockets) {

91

pingInterval = 20000

92

timeout = 15000

93

maxFrameSize = Long.MAX_VALUE

94

}

95

}

96

97

// Simple WebSocket connection

98

client.webSocket("wss://echo.websocket.org") {

99

// Send text message

100

send("Hello, WebSocket!")

101

102

// Receive messages

103

for (frame in incoming) {

104

when (frame) {

105

is Frame.Text -> {

106

val text = frame.readText()

107

println("Received: $text")

108

}

109

is Frame.Binary -> {

110

val bytes = frame.readBytes()

111

println("Received binary: ${bytes.size} bytes")

112

}

113

is Frame.Close -> {

114

println("Connection closed: ${frame.readReason()}")

115

break

116

}

117

}

118

}

119

}

120

121

// WebSocket with custom headers

122

client.webSocket({

123

url("wss://api.example.com/socket")

124

header("Authorization", "Bearer token123")

125

parameter("room", "chat-room-1")

126

}) { session ->

127

// Handle WebSocket session

128

session.send("JOIN room")

129

130

for (frame in incoming) {

131

// Process incoming frames

132

}

133

}

134

```

135

136

### ClientWebSocketSession

137

138

WebSocket session interface for client-side connections.

139

140

```kotlin { .api }

141

/**

142

* Client-side WebSocket session

143

*/

144

interface ClientWebSocketSession : WebSocketSession {

145

/** Associated HTTP client call */

146

val call: HttpClientCall

147

}

148

149

/**

150

* Default implementation of client WebSocket session

151

*/

152

class DefaultClientWebSocketSession(

153

private val call: HttpClientCall,

154

delegate: WebSocketSession

155

) : ClientWebSocketSession, WebSocketSession by delegate

156

157

/**

158

* Base WebSocket session interface

159

*/

160

interface WebSocketSession : CoroutineScope {

161

/** Incoming frames channel */

162

val incoming: ReceiveChannel<Frame>

163

164

/** Outgoing frames channel */

165

val outgoing: SendChannel<Frame>

166

167

/** WebSocket extensions */

168

val extensions: List<WebSocketExtension<*>>

169

170

/** Session close reason */

171

val closeReason: Deferred<CloseReason?>

172

173

/** Send text frame */

174

suspend fun send(content: String)

175

176

/** Send binary frame */

177

suspend fun send(content: ByteArray)

178

179

/** Send frame */

180

suspend fun send(frame: Frame)

181

182

/** Flush outgoing frames */

183

suspend fun flush()

184

185

/** Close the WebSocket connection */

186

suspend fun close(reason: CloseReason? = null)

187

188

/** Terminate the WebSocket connection immediately */

189

fun terminate()

190

}

191

```

192

193

### WebSocket Frames

194

195

Handle different types of WebSocket frames.

196

197

```kotlin { .api }

198

/**

199

* WebSocket frame types

200

*/

201

sealed class Frame {

202

/** Text frame containing UTF-8 text */

203

class Text(

204

val data: ByteArray,

205

val fin: Boolean = true,

206

val rsv1: Boolean = false,

207

val rsv2: Boolean = false,

208

val rsv3: Boolean = false

209

) : Frame() {

210

/** Read frame content as text */

211

fun readText(): String

212

213

/** Copy frame data */

214

fun copy(): ByteArray

215

}

216

217

/** Binary frame containing raw bytes */

218

class Binary(

219

val data: ByteArray,

220

val fin: Boolean = true,

221

val rsv1: Boolean = false,

222

val rsv2: Boolean = false,

223

val rsv3: Boolean = false

224

) : Frame() {

225

/** Read frame content as bytes */

226

fun readBytes(): ByteArray

227

228

/** Copy frame data */

229

fun copy(): ByteArray

230

}

231

232

/** Close frame with optional reason */

233

class Close(

234

val data: ByteArray = byteArrayOf()

235

) : Frame() {

236

/** Read close reason */

237

fun readReason(): CloseReason?

238

}

239

240

/** Ping frame for keep-alive */

241

class Ping(

242

val data: ByteArray

243

) : Frame()

244

245

/** Pong frame in response to ping */

246

class Pong(

247

val data: ByteArray

248

) : Frame()

249

}

250

251

/**

252

* WebSocket close reason

253

*/

254

data class CloseReason(

255

val code: Short,

256

val message: String

257

) {

258

companion object {

259

val NORMAL = CloseReason(1000, "Normal closure")

260

val GOING_AWAY = CloseReason(1001, "Going away")

261

val PROTOCOL_ERROR = CloseReason(1002, "Protocol error")

262

val CANNOT_ACCEPT = CloseReason(1003, "Cannot accept")

263

val NOT_CONSISTENT = CloseReason(1007, "Not consistent")

264

val VIOLATED_POLICY = CloseReason(1008, "Violated policy")

265

val TOO_BIG = CloseReason(1009, "Too big")

266

val NO_EXTENSION = CloseReason(1010, "No extension")

267

val INTERNAL_ERROR = CloseReason(1011, "Internal error")

268

val SERVICE_RESTART = CloseReason(1012, "Service restart")

269

val TRY_AGAIN_LATER = CloseReason(1013, "Try again later")

270

val TLS_HANDSHAKE_FAILED = CloseReason(1015, "TLS handshake failed")

271

}

272

}

273

```

274

275

**Usage Examples:**

276

277

```kotlin

278

client.webSocket("wss://api.example.com/chat") {

279

// Send different types of frames

280

send("Hello, chat!") // Text frame

281

send(byteArrayOf(1, 2, 3, 4)) // Binary frame

282

283

// Send custom frames

284

send(Frame.Ping(byteArrayOf()))

285

286

// Handle incoming frames

287

for (frame in incoming) {

288

when (frame) {

289

is Frame.Text -> {

290

val message = frame.readText()

291

println("Chat message: $message")

292

293

// Echo back

294

send("Echo: $message")

295

}

296

297

is Frame.Binary -> {

298

val data = frame.readBytes()

299

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

300

301

// Process binary data

302

processBinaryData(data)

303

}

304

305

is Frame.Close -> {

306

val reason = frame.readReason()

307

println("Connection closed: ${reason?.message}")

308

break

309

}

310

311

is Frame.Ping -> {

312

// Respond to ping with pong

313

send(Frame.Pong(frame.data))

314

}

315

316

is Frame.Pong -> {

317

println("Received pong")

318

}

319

}

320

}

321

}

322

```

323

324

### WebSocket Session Management

325

326

Advanced session management and connection handling.

327

328

```kotlin { .api }

329

/**

330

* Get WebSocket session from HTTP call

331

*/

332

suspend fun HttpClient.webSocketSession(

333

block: HttpRequestBuilder.() -> Unit = {}

334

): ClientWebSocketSession

335

336

suspend fun HttpClient.webSocketSession(

337

urlString: String,

338

block: HttpRequestBuilder.() -> Unit = {}

339

): ClientWebSocketSession

340

341

/**

342

* WebSocket session utilities

343

*/

344

suspend fun ClientWebSocketSession.receiveDeserialized<T>(): T

345

suspend fun ClientWebSocketSession.sendSerialized(data: Any)

346

```

347

348

**Usage Examples:**

349

350

```kotlin

351

// Get session without immediate processing

352

val session = client.webSocketSession("wss://api.example.com/socket") {

353

header("Authorization", "Bearer token")

354

}

355

356

try {

357

// Use session

358

session.send("Hello")

359

360

val response = session.incoming.receive()

361

when (response) {

362

is Frame.Text -> println(response.readText())

363

else -> println("Unexpected frame type")

364

}

365

} finally {

366

// Close session

367

session.close(CloseReason.NORMAL)

368

}

369

370

// With content negotiation

371

session.sendSerialized(ChatMessage("user1", "Hello everyone!"))

372

val message: ChatMessage = session.receiveDeserialized()

373

```

374

375

### WebSocket Extensions

376

377

Support for WebSocket protocol extensions.

378

379

```kotlin { .api }

380

/**

381

* WebSocket extension interface

382

*/

383

interface WebSocketExtension<ConfigType : Any> {

384

/** Extension name */

385

val name: String

386

387

/** Extension configuration */

388

val config: ConfigType

389

390

/** Process outgoing frame */

391

fun processOutgoingFrame(frame: Frame): Frame

392

393

/** Process incoming frame */

394

fun processIncomingFrame(frame: Frame): Frame

395

}

396

397

/**

398

* Common WebSocket extensions

399

*/

400

object WebSocketExtensions {

401

/** Deflate extension for compression */

402

val deflate: WebSocketExtension<DeflateConfig>

403

404

/** Per-message deflate extension */

405

val perMessageDeflate: WebSocketExtension<PerMessageDeflateConfig>

406

}

407

```

408

409

### Error Handling

410

411

Handle WebSocket-specific errors and exceptions.

412

413

```kotlin { .api }

414

/**

415

* WebSocket exception for connection errors

416

*/

417

class WebSocketException(

418

message: String,

419

cause: Throwable? = null

420

) : Exception(message, cause)

421

422

/**

423

* Exception for upgrade failures

424

*/

425

class WebSocketUpgradeException(

426

val response: HttpResponse

427

) : WebSocketException("WebSocket upgrade failed: ${response.status}")

428

429

/**

430

* Exception for protocol violations

431

*/

432

class WebSocketProtocolException(

433

message: String

434

) : WebSocketException(message)

435

```

436

437

**Usage Examples:**

438

439

```kotlin

440

try {

441

client.webSocket("wss://invalid-endpoint.example.com") {

442

send("Hello")

443

// Handle session

444

}

445

} catch (e: WebSocketUpgradeException) {

446

println("Failed to upgrade to WebSocket: ${e.response.status}")

447

} catch (e: WebSocketProtocolException) {

448

println("Protocol error: ${e.message}")

449

} catch (e: WebSocketException) {

450

println("WebSocket error: ${e.message}")

451

}

452

```

453

454

## Types

455

456

```kotlin { .api }

457

// WebSocket session types

458

interface WebSocketSession : CoroutineScope {

459

val coroutineContext: CoroutineContext

460

val incoming: ReceiveChannel<Frame>

461

val outgoing: SendChannel<Frame>

462

val extensions: List<WebSocketExtension<*>>

463

val closeReason: Deferred<CloseReason?>

464

}

465

466

// Delegating session implementation

467

class DelegatingClientWebSocketSession(

468

val delegate: WebSocketSession,

469

override val call: HttpClientCall

470

) : ClientWebSocketSession, WebSocketSession by delegate

471

472

// Content conversion types

473

interface WebsocketContentConverter {

474

suspend fun serialize(

475

charset: Charset,

476

typeInfo: TypeInfo,

477

value: Any?

478

): String

479

480

suspend fun deserialize(

481

charset: Charset,

482

typeInfo: TypeInfo,

483

content: String

484

): Any?

485

}

486

487

// Extension configuration types

488

data class DeflateConfig(

489

val serverMaxWindowBits: Int = 15,

490

val clientMaxWindowBits: Int = 15,

491

val serverNoContextTakeover: Boolean = false,

492

val clientNoContextTakeover: Boolean = false

493

)

494

495

data class PerMessageDeflateConfig(

496

val serverMaxWindowBits: Int = 15,

497

val clientMaxWindowBits: Int = 15,

498

val serverNoContextTakeover: Boolean = false,

499

val clientNoContextTakeover: Boolean = false,

500

val compressIfBiggerThan: Int = 1024

501

)

502

```