Skip to content

Commit 4e69341

Browse files
committed
sttp client/#902: document, that WebSocket.receive should only be used sequentially.
1 parent 28ed20d commit 4e69341

File tree

1 file changed

+39
-1
lines changed

1 file changed

+39
-1
lines changed

ws/src/main/scala/sttp/ws/WebSocket.scala

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ import sttp.model.Headers
44
import sttp.monad.MonadError
55
import sttp.monad.syntax._
66

7-
/** The `send*` and `receive*` methods may result in a failed effect, with either one of [[WebSocketException]]
7+
/** Effectful interactions with a web socket. Interactions can happen:
8+
*
9+
* - on the frame level, by sending and receiving raw [[WebSocketFrame]]s
10+
* - using the provided `receive*` methods to obtain concatenated data frames, or string/byte payloads, and the
11+
* `send*` method to send string/binary frames.
12+
*
13+
* The `send*` and `receive*` methods may result in a failed effect, with either one of [[WebSocketException]]
814
* exceptions, or a backend-specific exception. Specifically, they will fail with [[WebSocketClosed]] if the
915
* web socket is closed.
1016
*
@@ -19,13 +25,24 @@ trait WebSocket[F[_]] {
1925
* However, not all implementations expose the close frame, and web sockets might also get closed without the proper
2026
* close frame exchange. In such cases, as well as when invoking `receive`/`send` after receiving a close frame,
2127
* this effect will fail with the [[WebSocketClosed]] exception.
28+
*
29+
* *Should be only called sequentially!* (from a single thread/fiber). Because web socket frames might be fragmented,
30+
* calling this method concurrently might result in threads/fibers receiving fragments of the same frame.
2231
*/
2332
def receive(): F[WebSocketFrame]
33+
34+
/** Sends a web socket frame. Can be safely called from multiple threads.
35+
*
36+
* May result in a failed effect, in case of a network error, or if the socket is closed.
37+
*/
2438
def send(f: WebSocketFrame, isContinuation: Boolean = false): F[Unit]
2539
def isOpen(): F[Boolean]
2640

2741
/** Receive a single data frame, ignoring others. The frame might be a fragment.
2842
* Will fail with [[WebSocketClosed]] if the web socket is closed, or if a close frame is received.
43+
*
44+
* *Should be only called sequentially!* (from a single thread/fiber).
45+
*
2946
* @param pongOnPing Should a [[WebSocketFrame.Pong]] be sent when a [[WebSocketFrame.Ping]] is received.
3047
*/
3148
def receiveDataFrame(pongOnPing: Boolean = true): F[WebSocketFrame.Data[_]] =
@@ -40,6 +57,9 @@ trait WebSocket[F[_]] {
4057
/** Receive a single text data frame, ignoring others. The frame might be a fragment. To receive whole messages,
4158
* use [[receiveText]].
4259
* Will fail with [[WebSocketClosed]] if the web socket is closed, or if a close frame is received.
60+
*
61+
* *Should be only called sequentially!* (from a single thread/fiber).
62+
*
4363
* @param pongOnPing Should a [[WebSocketFrame.Pong]] be sent when a [[WebSocketFrame.Ping]] is received.
4464
*/
4565
def receiveTextFrame(pongOnPing: Boolean = true): F[WebSocketFrame.Text] =
@@ -51,6 +71,9 @@ trait WebSocket[F[_]] {
5171
/** Receive a single binary data frame, ignoring others. The frame might be a fragment. To receive whole messages,
5272
* use [[receiveBinary]].
5373
* Will fail with [[WebSocketClosed]] if the web socket is closed, or if a close frame is received.
74+
*
75+
* *Should be only called sequentially!* (from a single thread/fiber).
76+
*
5477
* @param pongOnPing Should a [[WebSocketFrame.Pong]] be sent when a [[WebSocketFrame.Ping]] is received.
5578
*/
5679
def receiveBinaryFrame(pongOnPing: Boolean = true): F[WebSocketFrame.Binary] =
@@ -62,6 +85,9 @@ trait WebSocket[F[_]] {
6285
/** Receive a single text message (which might come from multiple, fragmented frames).
6386
* Ignores non-text frames and returns combined results.
6487
* Will fail with [[WebSocketClosed]] if the web socket is closed, or if a close frame is received.
88+
*
89+
* *Should be only called sequentially!* (from a single thread/fiber).
90+
*
6591
* @param pongOnPing Should a [[WebSocketFrame.Pong]] be sent when a [[WebSocketFrame.Ping]] is received.
6692
*/
6793
def receiveText(pongOnPing: Boolean = true): F[String] =
@@ -70,6 +96,9 @@ trait WebSocket[F[_]] {
7096
/** Receive a single binary message (which might come from multiple, fragmented frames).
7197
* Ignores non-binary frames and returns combined results.
7298
* Will fail with [[WebSocketClosed]] if the web socket is closed, or if a close frame is received.
99+
*
100+
* *Should be only called sequentially!* (from a single thread/fiber).
101+
*
73102
* @param pongOnPing Should a [[WebSocketFrame.Pong]] be sent when a [[WebSocketFrame.Ping]] is received.
74103
*/
75104
def receiveBinary(pongOnPing: Boolean): F[Array[Byte]] =
@@ -114,7 +143,16 @@ trait WebSocket[F[_]] {
114143
}
115144
}
116145

146+
/** Sends a web socket frame with the given payload. Can be safely called from multiple threads.
147+
*
148+
* May result in a failed effect, in case of a network error, or if the socket is closed.
149+
*/
117150
def sendText(payload: String): F[Unit] = send(WebSocketFrame.text(payload))
151+
152+
/** Sends a web socket frame with the given payload. Can be safely called from multiple threads.
153+
*
154+
* May result in a failed effect, in case of a network error, or if the socket is closed.
155+
*/
118156
def sendBinary(payload: Array[Byte]): F[Unit] = send(WebSocketFrame.binary(payload))
119157

120158
/** Idempotent when used sequentially.

0 commit comments

Comments
 (0)