Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Websocket keep track of connections in Spring

Today I've searched a couple of hours for an implementation or tutorial in how to keep track of websocket connections in Spring.

I've done the (very good) Spring tutorial about websockets and STOMP. link here

So what's my setup, I have an Ionic Hybrid app with an Spring backend and I want to send a notification to the client whenever a new notification-event arises in the backend. All this code is already implemented and the connection works, but right now there is no way to specify where the notifications need to go to.

There is no tutorial or explanation on this matter that follows the structure in the Spring tutorial (at least not after 5 hours of research) and I am a little overwhelmed by all the information about websockets and security on the web. (I've been learning about websockets for just 2 days)

So for all that been before me and will come after me, I think it can be very usefull to have a compact and lightweight answer following the structure taught by the Spring Tutorial.

I've found this unanswered question on StackOverflow about the same problems as I have, so I'm sure this questions will prove it's worth.

TL;DR

How to implement a list in the backend that keeps track of the connections based on the Spring WebSocket Tutorial?

How to send data from the client to the backend when the connection is established? (for example a userid or token)

like image 364
Sytham Avatar asked Aug 02 '16 13:08

Sytham


People also ask

Does WebSocket keep connection open?

WebSockets keeps a single, persistent connection open while eliminating latency problems that arise with HTTP request/response-based methods. WebSockets generally do not use XMLHttpRequest, and as such, headers are not sent every-time we need to get more information from the server.

Would WebSockets be able to handle 1000000 concurrent connections?

The answer is complicated by several factors, but 1,000,000 simultaneous active socket connections is possible for a properly sized system (lots of CPU, RAM and fast networking) and with a tuned server system and optimized server software.

How do you use WebSockets in Spring?

In order to tell Spring to forward client requests to the endpoint , we need to register the handler. Start the application- Go to http://localhost:8080 Click on start new chat it opens the WebSocket connection. Type text in the textbox and click send. On clicking end chat, the WebSocket connection will be closed.

How do I know if a WebSocket is connected?

You can check if a WebSocket is connected by doing either of the following: Specifying a function to the WebSocket. onopen event handler property, or; Using addEventListener to listen to the open event.


1 Answers

So I figured it out myself.

My notifications have a recipient id (the user id where the notifications needs to be send to)

So I'm going to send to '/ws-user/'+id+'/greetings' where the id is the user that is logged in.

On the clientside this is fairly easy to achieve.

 var stompClient = null;

  // init
  function init() {
          /**
           * Note that you need to specify your ip somewhere globally
           **/
      var socket = new SockJS('http://127.0.0.1:9080/ws-notification');
      stompClient = Stomp.over(socket);
      stompClient.connect({}, function(frame) {
          console.log('Connected: ' + frame);
          /**
           * This is where I get the id of the logged in user
           **/
          barService.currentBarAccountStore.getValue().then(function (barAccount) {
              subscribeWithId(stompClient,barAccount.user.id);
          });
      });
  }

          /**
           * subscribe at the url with the userid
           **/
  function subscribeWithId(stompClient,id){
      stompClient.subscribe('/ws-user/'+id+'/greetings', function(){
          showNotify();
      });
  }
          /**
           * Broadcast over the rootscope to update the angular view 
           **/
  function showNotify(){
      $rootScope.$broadcast('new-notification');
  }

  function disconnect() {
      if (stompClient != null) {
          stompClient.disconnect();
      }
      // setConnected(false);
      console.log("Disconnected");
  }

Next up we add "setUserDestinationPrefix" to the MessageBrokerRegistry in the WebSocketConfig.java class :

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    private final static String userDestinationPrefix = "/ws-user/";

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config){
        config.enableSimpleBroker("/ws-topic","/ws-user");
        config.setApplicationDestinationPrefixes("/ws-app");
        config.setUserDestinationPrefix(userDestinationPrefix);
    }

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

Note that I'm using internal RestTemplate calls to access my controllermethod that sends out a notification to the subscribed client. This is done by a Event Consumer class (ask to see code, it's just to trigger controller function, could be done differently)

@RequestMapping(value = "/test-notification", method = RequestMethod.POST)
public void testNotification(@RequestBody String recipientId) throws InterruptedException {
    this.template.convertAndSendToUser(recipientId,"/greetings", new Notify("ALERT: There is a new notification for you!"));
}

Please review my code and warn me if you see any issues and/or security concerns.

like image 151
Sytham Avatar answered Oct 15 '22 10:10

Sytham