0

I have an application with WebSockets using spring-boot application as backend and Stomp/SockJS in the client side, the spring-boot application consume JMS queue messages and notify the changes to the right user. What is the problem? Sometimes works and sometimes doesn't work, same code and users could work or not.

The client side code is a bit more difficult to copy here because it's integrate over react/redux application but basically is a subscription to two different channels, both defined in the configuration of Spring. The sessions are created correctly according to debug information but just sometimes the message is processed to send it to connected sessions.

This is the configuration class for Spring.

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

   @Override
   public void registerStompEndpoints(StompEndpointRegistry registry) {

      registry
         .addEndpoint("/stomp")
         .setAllowedOrigins("*")
         .withSockJS();
   }

   public void configureMessageBroker(MessageBrokerRegistry registry) {

      registry
         .setApplicationDestinationPrefixes("/app")
         .enableSimpleBroker("/xxxx/yyyy", "/ccccc");
   }

   @Override
   public void configureClientInboundChannel(ChannelRegistration registration) {

      registration.interceptors(new ChannelInterceptor() {

         @Override
         public Message<?> preSend(Message<?> message, MessageChannel channel) {

             StompHeaderAccessor accessor =
                     MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

             if (StompCommand.CONNECT.equals(accessor.getCommand())) {
                 Object raw = message
                         .getHeaders()
                         .get(SimpMessageHeaderAccessor.NATIVE_HEADERS);

                 if (raw instanceof Map) {
                     Object name = ((Map<?,?>) raw).get("email");

                     if (name instanceof LinkedList) {
                         String user = ((LinkedList<?>) name).get(0).toString();
                         accessor.setUser(new User(user));
                     }
                 }
             }
             return message;
         }
      });
   }
}

This is the JMS listener to process queue message and send it to specific user.

@Component
public class UserEventListener {

   private final Logger logger = LoggerFactory.getLogger(getClass());
   private final SimpMessagingTemplate template;

   @Autowired
   public UserEventListener(SimpMessagingTemplate pTemplate) {
      this.template = pTemplate;
   }

   @JmsListener(destination="user/events")
   public void onStatusChange(Map<String, Object> props) {

      if (props.containsKey("userEmail")) {
         logger.debug("Event for user received: {}", props.get("userEmail"));
         template.convertAndSendToUser((String)props.get("userEmail"), "/ccccc", props);
      }
   }
}

Edit 1:

After more debugging the times when doesn't work the "session" for WebSocket seems to be lost by Spring configuration. I don't see any log information about "Disconnected" messages or something similar, besides if I debug remotely the server when this happens the problem doesn't appears during debugging session. Some idea? The class from Spring where session disappear is DefaultSimpUserRegistry.

fjtorres
  • 266
  • 6
  • 13
  • Debugging more internally show something strange, userRegistry with relationships between users and session is empty sometimes however I can see `Processing SUBSCRIBE` and `Processing CONNECT` lines in log files before receive events. – fjtorres Aug 23 '19 at 11:30

1 Answers1

0

After more research I found a question with the same problem and the solution here. Basically the conclusion is this:

Channel interceptor is not the right place to authenticate user, we need to change it with a custom handshake handler.

fjtorres
  • 266
  • 6
  • 13