-
Notifications
You must be signed in to change notification settings - Fork 564
WebSockets Support: Tyrus Integration
This document describes a prototype integration of Tyrus and Helidon.
Tyrus is the reference implementation of JSR 356: Java API for WebSocket. It provides both a client and a server API to communicate using WebSockets using Java. In addition, the JSR defines an SPI to integrate implementations with HTTP containers/connectors. This document focuses on the server API in JSR 356.
A WebSocket connection starts as a normal HTTP connection that is subsequently upgraded to use WebSockets, essentially turning an HTTP connection into a plain TCP connection. JSR 356 provides an API to not only send and received messages over a WebSockets connection but also an API to intercept the HTTP upgrade request and potentially alter its outcome --all JSR implementations provided a default upgrade handler.
Yes, Netty has support for WebSockets. However, there's an overlap between this support in Netty and what Tyrus provides. For example, both the Netty's handlers and Tyrus provide support for protocol upgrades and both handle codecs for different types of messages.
In order to support JSR 356 in Helidon, we need to limit Netty's involvement in handling connections to a minimum and let Tyrus do its work. In particular, we need protocol upgrade to be handled by Tyrus (or the application handler as supported by the JSR 356 API) and for Netty to simply, and most importantly opaquely, relay WebSocket messages to connection peers.
A connection upgrade starts a regular HTTP request with some special headers. As stated above, this request must be forward it to Tyrus for it to intervene in the upgrade process: this can be accomplished by simply setting up the regular Netty pipeline without any special handlers for WebSockets.
The response to this initial upgrade request needs to be interecepted by Helidon in order to detect a successful upgrade, in which case, Netty's pipeline needs to be modified so that WebSockets can be relayed over the now upgraded connection. In particular, HTTP handlers in Netty's pipeline need to be replaced by handlers capable of relaying WebSocket messages.
After a connection is upgraded, WebSocket messages are allowed to flow over a full-duplex channel. These messages are intended to be processed by Tyrus and must not be interpreted by Netty. After updating the Netty pipeline accordingly, Helidon's implementation of Tyrus' SPI can simply register a Flow.Publisher
for server-to-client messages and a Flow.Subscriber
for client-to-server ones. This is the responsibility of the TyrusSupport
class --akin to JerseySupport
.
@ServerEndpoint("/echo")
public class EchoEndpoint {
@OnOpen
public void onOpen(Session session) throws IOException {
session.getBasicRemote().sendText("onOpen");
}
@OnMessage
public void echo(Session session, String message) throws IOException {
session.getBasicRemote().sendText(message + " (from your server)");
}
@OnError
public void onError(Throwable t) {
}
@OnClose
public void onClose() {
}
}