kaqqao
kaqqao

Reputation: 15439

How to implement a custom WebSocket subprotocol with Spring

I have to add support for a custom WebSocket subprotocol (so not STOMP) in a Spring Boot application, but I'm having a very hard time understanding what I need to provide and what Spring already has.

This is how far I got:

@Configuration
@EnableWebSocket
public class WebSocketAutoConfiguration implements WebSocketConfigurer {

    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
        webSocketHandlerRegistry.addHandler(this.webSocketHandler(), new String[]{endpointUrl});
    }

    @Bean
    public WebSocketHandler webSocketHandler() {
        ExecutorSubscribableChannel clientInboundChannel = new ExecutorSubscribableChannel();
        ExecutorSubscribableChannel clientOutboundChannel = new ExecutorSubscribableChannel();
        SubProtocolWebSocketHandler subProtocolWebSocketHandler = new SubProtocolWebSocketHandler(clientInboundChannel, clientOutboundChannel);
        subProtocolWebSocketHandler.addProtocolHandler(new SubProtocolHandler() {
            public List<String> getSupportedProtocols() {
                return Collections.singletonList("custom-protocol");
            }

            public void handleMessageFromClient(WebSocketSession session, WebSocketMessage<?> message, MessageChannel outputChannel) throws Exception {
                session.sendMessage(new TextMessage("some message"));
            }

            public void handleMessageToClient(WebSocketSession session, Message<?> message) throws Exception {
            }

            public String resolveSessionId(Message<?> message) {
                return UUID.randomUUID().toString();
            }

            public void afterSessionStarted(WebSocketSession session, MessageChannel outputChannel) throws Exception {
                System.out.println("SESSION STARTED");
            }

            public void afterSessionEnded(WebSocketSession session, CloseStatus closeStatus, MessageChannel outputChannel) throws Exception {
                session.close();
                System.out.println("SESSION ENDED");
            }
        });
        return subProtocolWebSocketHandler;
    }
}

This works, in the sense that handleMessageFromClient does get triggered on a web socket message, but I fail to understand the purpose of MessageChannel outputChannel and handleMessageToClient.

Is it possible to get the PerConnectionWebSocketHandler semantics with SubProtocolWebSocketHandler?

The documentation around this is basically non-existent e.g. the docs for handleMessageToClient say:

Handle the given {@link Message} to the client associated with the given WebSocket session.

Well, fantastic. And the STOMP implementations are mind-boggling, so they're not very usable as a guideline.

Any example, broad steps or anything, really, would be much appreciated.

Upvotes: 6

Views: 4924

Answers (1)

kaqqao
kaqqao

Reputation: 15439

Turns out it is exceptionally easy. No need to mess with SubProtocolWebSocketHandler at all. The only requirement is that the provided WebSocketHandler implements SubProtocolCapable.

public class CustomHandler implements WebSocketHandler, SubProtocolCapable {
   ...
}

That's all. To make a PerConnectionWebSocketHandler, it's enough to simply extend it and implement SubProtocolCapable:

public class CustomHandler extends PerConnectionWebSocketHandler implements SubProtocolCapable {
   ...
}

Upvotes: 4

Related Questions