Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring STOMP server without SockJS/StompJS

I have Spring server with Spring Websocket support. I would like to use STOMP sub-protocol to handle communication over web sockets, so the configuration of STOMP endpoint looks as follow:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/chat")
                .setAllowedOrigins("*")
                .withSockJS();
    }
}

Spring documentation and basically any resource on the topic I was able to find shows how to create STOMP client using SockJS + StompJS. It works but as I understand it shouldn't be needed at all - as STOMP is just a sub-protocol I should be able to communicate with my server basically from any web socket client just by using STOMP messages syntax.

Let's say I just want to connect to my STOMP server from Google Chrome Simple Web Socket Client addon. Accordingly to the STOMP specification first thing which I do is opening web socket connection. I do it with

ws://my.server.here/chat/websocket

link. This part works and my connection is established. Now I want to use STOMP. Again as STOMP specification says I should now send CONNECT command which looks as follows (STOMP 1.1):

CONNECT
accept-version:1.0,1.1
host:my.host.here

^@

Then I would expect response from server with CONNECTED command but I get nothing. If instead of "CONNECT" I will use some non-existing command like "WRONG_COMMAND" then I can see Spring exception being thrown about unknown command, so I suppose that my message hits Spring's Websocket internals but I'm unable to get anything back. If this would work I would like to use subsequent SEND, SUBSCRIBE etc. commands to perform operations.

Is this kind of workflow even possible? Am I doing something wrong or maybe I wrongly undrestood the whole idea and the way in which it works?

like image 871
Plebejusz Avatar asked Apr 20 '17 14:04

Plebejusz


1 Answers

I have solved the issue, so short answer is yes, you can use Spring's STOMP messaging without SockJS, just by sending appropriate constructed messages to the websocket endpoint.

Longer answer is that I was unable to do this with Google Simple Websocket Client, as the ^@ character from STOMP syntax means, quoting from STOM documentation:

examples in this document will use ^@, control-@ in ASCII, to represent the NULL octet.

The problem with Google's Websocket Client was, as I think, that I wasn't really able to send this null octet with it, so my STOMP messages weren't correctly terminated.

I needed it for simple chat for a mobile app that couldn't use SockJS and with help of my company mobile developer we were able to write working solution, which is basically just a message formatter compatible with STOMP sub-protocol.

We used Xamarin with C# for mobile app development. Connecting to the STOMP is done like this. Notice that we first open regular connection to the websocket, and we go to STOMP handling when it's established:

var connectString = String.Format("CONNECT\naccept-version:1.0,1.1\nlogin:{0}\nheart-beat:30000,0\n\n\0", AuthService.TOKEN);
webSocketConnection = Websockets.WebSocketFactory.Create();
webSocketConnection.OnOpened += () => 
{
    webSocketConnection.Send(connectString);
    Debug.WriteLine("opened");
};

You will have to handle responses from server with your client onMessage method or it's equivalent. When connection is established you can send STOMP messages like this, for example as we do it in our app:

var messageString = String.Format("SEND\ndestination:/app/chat/send/{0}\nlogin:{1}\n\n{{\"message\":\"{2}\"}}\n\0", chatName, AuthService.TOKEN, message);
webSocketConnection.Send(messageString);

Also remember that you probably will need to support heartbeat, so backend side won't disconnect your app thinking that it's dead. In our mobile app we send heartbeats from another thread. Heartbeat is just a newline meassage sent to the websocket address. Notice that it does not contain any STOMP headers etc.:

webSocketConnection.Send("\n");

We used this as our websocket client.

This is just base on which we built full support for connection with Spring's Websockets without SockJS, feel free to ask if you have further questions. Credits to Mateusz Gaffke for helping with and implementing mobile side.

like image 181
Plebejusz Avatar answered Oct 23 '22 03:10

Plebejusz