1

I am using STOMP over websockets with spring boot. Is there a possibility to send a message to a specific subscription? I subscribe to the STOMP endpoints using a STOMP header containing an id field according to the stomp documentation I want this id to be used to determine the clients who should receive a message, but spring seems not to use this id. I can not just use sendToUser because two clients can have the same user id e.g. if a user has two opened browser windows. Only one specific window should receive the message.

In the following example I have two connected clients which are using the same user, but different ids in the STOMP header.

Client1-ID: a32d66bf-03c7-47a4-aea0-e464c0727842

Client2-ID: b3673d33-1bf2-461e-8df3-35b7af07371b

In spring I have executed the following Kotlin code:

val subscriptions =  userRegistry.findSubscriptions {
            it.destination == "/user/topic/operations/$operationId/runs"
        }
        subscriptions.forEach{
            println("subscription id: ${it.id}");
            println("session id: ${it.session.id}");
            println("user id ${it.session.user.name}");
        }

The output:

subscription id: sub-7
session id: mcjpgn2i
user id 4a27ef88-25eb-4175-a872-f46e7b9d0564
subscription id: sub-7
session id: 0dxuvjgp
user id 4a27ef88-25eb-4175-a872-f46e7b9d0564

There is no sign of the id I have passed to the stomp header.

Is it possible to send a message to one specific subscription determined by the id I have passed with the header?

Jonas Erbe
  • 177
  • 1
  • 12

2 Answers2

-1

I got it working.

First of all, there was something wrong with my client setup. I have set the subscription id in the connection header like this:

this.stompClient.webSocketFactory = (): WebSocket => new SockJS("/ws");
this.stompClient.connectHeaders = { id: subscriptionId };
this.stompClient.activate();

But the subscription header has to be set in the subscription header:

this.stompClient.subscribe(this.commonEndpoint,
        this.onMessageReceived.bind(this),
        { id: subScriptionId });

If I do this, spring is correctly using this id as the subscription id, instead of using some default like sub-7.

According to that thread I can send messages to specific sessions instead of user.

With the following code I can send a message to a specific subscription:

val subscriptions = userRegistry.findSubscriptions {
            it.destination == "/user/topic/operations/$operationId/runs"
        }
subscriptions.forEach {
    if(it.id === mySubscriptionId){
        val headerAccessor = 
        SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE)
        headerAccessor.sessionId = it.session.id
        headerAccessor.setLeaveMutable(true)

        simpMessagingTemplate.convertAndSendToUser(it.session.id,  
            "/topic/operations/runs", messageResponseEntity,
            headerAccessor.getMessageHeaders())

     }
}
Jonas Erbe
  • 177
  • 1
  • 12
  • 1
    I think this code picks up a 'specific' subscription, okay fine, BUT then sends a message to the session (more like user-, or even connection-level) which that subscription belongs to. So if you have sub-1 and sub-2 in a session, you cannot send a message to sub-2 only using this code.. So it _appears_ working in your case since you have two sub-7s (doesn't matter much if subs are both 7 or distinct numbers) but they belong to sessions mcjpgn2i and 0dxuvjgp. If instead subs shared a session, you'd be sending to both. Just posting as I'm trying to get this to work as well... no luck yet! – almondandapricot Jan 31 '21 at 04:06
-1

I'm able to send message to a specific subscription using SimpMessagingTemplate.

    @Autowired
    private final SimpMessagingTemplate messagingTemplate;


    public void sendMessage(String simpUserId, String destination, String message) {
        try {
            messagingTemplate.convertAndSendToUser(simpUserId, destination, message);
        } catch (Exception ex) {
            LOG.error("Exception occurred while sending message [message={}]", ex.getMessage(), ex);
        }
    }

You may refer SimpMessagingTemplate.convertAndSendToUser

kulsin
  • 398
  • 4
  • 18
  • This is not a solution. As I wrote above the same user could have opened two browser windows. But only one window should receive the websocket message. – Jonas Erbe Oct 28 '22 at 06:44