Search code examples
springrestrabbitmqspring-websocketspring-rabbit

Custom destination with RabbitMQ


I'm trying to use RabbitMQ as a broker on my project and I want to assign the destination queue when I open the socket on the client side. Something like this: https://i.sstatic.net/ViTF5.png

I managed to do it with SimpleBroker, however when I try to do it with StompBrokerRelay I can't assing the queue on RabbitMQ and I stop receiving messages on the client (https://i.sstatic.net/BawYT.png).

This is how I'm doing it:

Controller:

@RestController
public class FeedController {

@Autowired
private SimpMessageSendingOperations template;

    @RequestMapping(value = "/feed",  method = RequestMethod.POST, consumes = "application/json")
    public Reference getLeankrReference(@RequestBody Reference ref)
    {       
        this.template.convertAndSendToUser(ref.getChannelId(), "/topic/feed", ref);
        return ref;
    }
}

Websocket configuration:

@Configuration
@EnableWebSocketMessageBroker
@EnableScheduling
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config)
    {
        config.enableStompBrokerRelay("/topic/")
            .setAutoStartup(true);

        //config.enableSimpleBroker("/user/");
        config.setApplicationDestinationPrefixes("/app");
    }

    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/vision").withSockJS();
    }
}

Client:

        function connect() {
        var socket = new SockJS('/ws/vision');
        var channel = document.getElementById('name').value;
        stompClient = Stomp.over(socket);

        stompClient.connect({}, function(frame) {
            setConnected(true);
            console.log('Connected: ' + frame);
            stompClient.subscribe('/user/' + channel + '/feed', function(message) {
                showContent(JSON.parse(message.body));
            });
        });
    }

I know that I'm missing something. Maybe some broker config?

Thank you in advance!


Solution

  • Finally, I figured out what I was missing!

    Websocket configuration:

    I was only assigning the topic queue. In this case, I need also the queue queue, once I want to assign it to a specific user/channel.

    config.enableStompBrokerRelay("/queue/", "/topic/");
    

    Client:

    I wasn't referring the type of queue that I wanted to use.

    stompClient.subscribe('/user/queue/feed', function(content) {

    But this was not enough. It was missing the correct security configuration.

    Something like this,

    Security configuration:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .headers().addHeaderWriter(
                new XFrameOptionsHeaderWriter(
                        XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN)).and()
            .formLogin()
                .defaultSuccessUrl("/index.html")
                .loginPage("/login.html")
                .failureUrl("/login.html?error")
                .permitAll()
                .and()
            .logout()
                .logoutSuccessUrl("/login.html?logout")
                .logoutUrl("/logout.html")
                .permitAll()
                .and()
            .authorizeRequests()
                .antMatchers("/**").permitAll()
                .anyRequest().authenticated()
                .and();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("channel1").password("password").roles("USER");
    }
    

    With that I added a login page. Which is not necessary. You just need to ensure that the password parameter is used for authentication.

    Now that Rabbit knows the user/channel, it can send queues to specific destinations.