It's worth noting that the WebSocket
itself is just a dumb container. The magic happens in various classes within play.core.server.netty
.
To understand what that magic is, it's instructive to look at the signature of f (the function that a WebSocket
contains:
RequestHeader => (Enumerator[A], Iteratee[A, Unit]) => Unit
This is a function that takes a RequestHeader
, an Enumerator
, and an Iteratee
, and does something with them.
So, at some point in the future, the framework will provide our WebSocket
with a RequestHeader
(which should be self explanatory), an Enumerator[A]
(Enumerators are sources, in this case, these are the messages being received from the client), and an Iteratee[A, Unit]
(Iteratees are sinks, in this case, this is where we send messages to go back to the client).
In the case of WebSocket.adapter
, the WebSocket will connect the Enumerator
to the Iteratee
via an Enumeratee
. In the case of WebSocket.using
, the WebSocket will connect the remote Enumerator
to a local Iteratee
, and connect the remove Iteratee
to a local Enumerator
.
Rather than defining WebSocket directly, it's likely to be easier to use one of the convenience methods in the WebSocket
object. The following code will echo the previous message received:
def mySocket = WebSocket.adapter {implicit req =>
var lastMessage = "No previous message"
Enumeratee.map[String] {msg =>
val response = lastMessage
lastMessage = msg
response
}
}
Note that this code almost certainly has thread safety issues - in Scala, you should try to avoid mutable state whenever possible, or use actors or similar if not.
Or, try WebSocket.using
, and look at a pushee Enumerator
, in conjunction with a foreach Iteratee
, although it's a little fiddler. Perhaps understandably, the pushee enumerator is deprecated in Play 2.1, as it's being superseded by the new channels system.