From d6cae89d2dc92f516cc6269bec994bc3b4a48a2b Mon Sep 17 00:00:00 2001 From: kciesielski Date: Fri, 24 May 2024 10:17:49 +0200 Subject: [PATCH] Add documentation --- docs/websockets.md | 51 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/docs/websockets.md b/docs/websockets.md index c3bb562803..0e96b6cca3 100644 --- a/docs/websockets.md +++ b/docs/websockets.md @@ -95,6 +95,55 @@ effect type class name ================ ========================================== ``` +## WebSockets as Ox Source and Sink + +[Ox](https://ox.softwaremill.com) is a Scala 3 toolkit that allows you to handle concurrency and resiliency in direct-style, leveraging Java 21 virtual threads. +If you're using Ox with `sttp`, you can use the `DefaultSyncBackend` from `sttp-core` for HTTP communication. An additional `ox` module allows handling WebSockets +as Ox `Source` and `Sink`: + +``` +// sbt dependency +"com.softwaremill.sttp.client4" %% "ox" % "@VERSION@", +``` + +```scala +import ox.* +import ox.channels.{Sink, Source} +import sttp.client4.* +import sttp.client4.impl.ox.ws.* // import to access asSourceAnkSink +import sttp.client4.ws.SyncWebSocket +import sttp.client4.ws.sync.* +import sttp.ws.WebSocketFrame + +def useWebSocket(ws: SyncWebSocket): Unit = + supervised { + val (wsSource, wsSink) = asSourceAndSink(ws) // (Source[WebSocketFrame], Sink[WebSocketFrame]) + // ... + } + +val backend = DefaultSyncBackend() +basicRequest + .get(uri"wss://ws.postman-echo.com/raw") + .response(asWebSocket(useWebSocket)) + .send(backend) +``` + +See the [full example here](https://github.com/softwaremill/sttp/blob/master/examples/src/main/scala/sttp/client4/examples3/WebSocketOx.scala). + +Make sure that the `Source` is contiunually read. This will guarantee that server-side Close signal is received and handled. +If you don't want to process frames from the server, you can at least handle it with a `fork { source.drain() }`. + +You don't need to manually call `ws.close()` when using this approach, this will be +handled automatically underneath, according to following rules: + - If the request `Sink` fails with an error, the `Source` is automatically completed, sending a `Close` frame to + the server if needed. + - If the request `Sink` completes without an error, a `Close` frame is sent, and the response `Sink` keeps + receiving responses until the server closes communication. + - If the response `Source` is completed (either due to completion or an error), the request Sink is completed, + right after sending all outstanding buffered frames. + +Read more about Ox, structured concurrency, Sources and Sinks on the [project website](https://ox.softwaremill.com). + ## Compression For those who plan to use a lot of websocket traffic, you could consider websocket compression. See the information on @@ -122,4 +171,4 @@ Web socket settings can be adjusted by providing a custom `AsyncHttpClientConfig Some available settings: * maximum web socket frame size. Default: 10240, can be changed using `.setWebSocketMaxFrameSize`. -* compression. Default: false, can be changed using: `.setEnablewebSocketCompression`. \ No newline at end of file +* compression. Default: false, can be changed using: `.setEnablewebSocketCompression`.