Socket
Websocket support can be added to your Http application using the same Http
domain, something like this —
import zio.http._
import zio._
val socket = Handler.webSocket { channel =>
channel.receiveAll {
case ChannelEvent.Read(WebSocketFrame.Text("foo")) =>
channel.send(ChannelEvent.Read(WebSocketFrame.text("bar")))
case _ =>
ZIO.unit
}
}
val http = Routes(
Method.GET / "subscriptions" -> handler(socket.toResponse)
)
The WebSocket API leverages the already powerful Http
domain to write web socket apps. The difference is that instead
of collecting Request
we collect Channel
or more specifically WebSocketChannel
. And, instead of
returning
a Response
we return Unit
, because we use the channel to write content directly.
Channel
Essentially, whenever there is a connection created between a server and client a channel is created on both sides. The channel is a low level api that allows us to send and receive arbitrary messages.
When we upgrade a Http connection to WebSocket, we create a specialized channel that only allows websocket frames to be
sent and received. The access to channel is available through the Channel
api.
ChannelEvents
A ChannelEvent
is an immutable, type-safe representation of an event that's happened on a channel, and it looks like
this:
sealed trait ChannelEvent[A]
It is the Event that was triggered. The type param A
on the ChannelEvent represents the kind of message the event contains.
The type WebSocketChannelEvent
is a type alias to ChannelEvent[WebsocketFrame]
. Meaning an event that contains WebSocketFrame
typed messages.
Using Http
We can use Http.collect
to select the events that we care about for our use case, like in the above example we are
only interested in the ChannelRead
event. There are other life cycle events such as ChannelRegistered
and ChannelUnregistered
that one might want to hook onto for some other use cases.