springwebsocketstompsockjs

Spring websocket: how to send to all subscribers except the message sender


I am following the quick-start guide on Spring websocket with sockJs and Stomp here: https://spring.io/guides/gs/messaging-stomp-websocket/

At this point, my code looks like to one from guide and works as intended. I have a controller class with a method accepting incoming messages and sending them back to all who subscribed on the topic.

What I want to do, is to change the code, so my @MessageMapping annotated method sends response to all subscribers excluding the one who send the message to the controller in the first place (because the sender is also subscribed to the same topic, but i dont want the sender to keep receiving messages it send itself, it is kind of a loop I guess).

I have seen many docs describing how to send a message to a single subscriber, but have not yet seen on describing how to send to all but one - the initial message sender.

Is there any built-in way to do this easily in Spring websocket?


Solution

  • Ok so i've managed to find some solution which works for me at this point of time:

    i was able to filter subscribers by principal user name.

    I got all simp users form org.springframework.messaging.simp.user.SimpUserRegistry, and a current sender from org.springframework.messaging.simp.stomp.StompHeaderAccessor.

    My code looks something like this:

      @MessageMapping("/game/doStuff")
      public void gameGrid(DoStuffMessage doStuffMessage,
          StompHeaderAccessor headers) {
        sendTo("/game/doStuff", doStuffMessage, headers);
      }
    
      private void sendTo(String destination, Object payload, StompHeaderAccessor headers) {
        Optional<String> user = Optional.ofNullable(headers.getUser())
            .map(Principal::getName);
    
        if (user.isPresent()) {
          List<String> subscribers = simpUserRegistry.getUsers().stream()
              .map(SimpUser::getName)
              .filter(name -> !user.get().equals(name))
              .collect(Collectors.toList());
    
          subscribers
              .forEach(sub -> simpMessagingTemplate.convertAndSendToUser(sub, destination, payload));
        }
      }
    

    Client is subscribing to /user/game/doStuff

    It works for now. What I am worried about is if this code can scale horizontally - if someone has any insight on this I'd greatly appreciate that.