Отправка сообщения websocket пользователю через dynos - PullRequest
0 голосов
/ 12 апреля 2019

У меня приложение весенней загрузки, работающее на героку. Я использую веб-сокеты для отправки сообщений клиенту и серверу для конкретного пользователя. Я использую весенний загрузчик SimpMessagingTemplate.convertAndSendToUser для отправки и получения сообщений, который отлично работает, когда пользователю необходимо получить сообщение обратно с сервера. Я использую схожесть сеансов Heroku, что означает, что даже если я увеличу количество сеансов, пользователь и веб-сокет будут использовать один и тот же сеанс.

Моя проблема возникает, когда мне нужно, чтобы пользователь отправил сообщение другому пользователю. Это работает нормально, если оба пользователя совместно используют сеанс, но не, если сообщение не приходит.

Можно ли отправить сообщение от одного пользователя другому через разные сеансы, используя SimpMessagingTemple? Или мне нужно использовать брокер сообщений, например, Redis.

Я пытался реализовать отправку сообщения с использованием StringRedisTemplate, но не знал, как отправить сообщение конкретному пользователю.

    private SimpMessagingTemplate messagingTemplate;
    @Autowired
    public MessageController(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    @MessageMapping("/secured/user-in")
    public void sendToDevice(Message msg, @AuthenticationPrincipal User principal) throws Exception {

        if (msg.getTo() != null) {
        String email = msg.getTo();
        Message out = new Message();
        out.setMsg(msg.getMsg());
        out.setFrom(msg.getFrom());
        out.setTo(msg.getTo());
        out.setSentTime(new Date());
        out.setStatus(msg.getStatus());
        messagingTemplate.convertAndSendToUser(email, "/secured/topic", out);
        }       

    }

JS

function connect() {
    var socket = new SockJS('/secured/user-in');
    ST.stompClient = Stomp.over(socket);
    var headers = {};
    headers[ST.getHeader()] = ST.getToken();

    ST.getStompClient().connect(headers, function (frame) {
        retries = 1;
        console.log('Connected: ' + frame);
        ST.getStompClient().subscribe('/user/secured/topic', function (event){

            var msg = JSON.parse(event.body);
            showMessage(msg.msg); 

        });

    }); 

}

ОБНОВЛЕНИЕ 1

Полагаю, я мог бы сделать что-то подобное, как сделано здесь :

    SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor
.create(SimpMessageType.MESSAGE);
    headerAccessor.setSessionId(sessionId);
    headerAccessor.setLeaveMutable(true);

    messagingTemplate.convertAndSendToUser(sessionId,"/queue/something", payload, 
    headerAccessor.getMessageHeaders());

Но как я могу получить идентификатор сеанса другого пользователя, я использую Redis для хранения информации о сеансе: @ EnableRedisHttpSession

1 Ответ

0 голосов
/ 13 апреля 2019

Я немного перепутал свою терминологию. Я пытался отправить сообщение другому пользователю на другом компьютере, а не на сеансе.

Завершено с использованием redis sub / pub.

Поэтому, когда сообщение получено контроллером, оно публикуется в redis, а метод redL MessageListenerAdapter вызывает метод convertAndSendToUser.

@MessageMapping("/secured/user-in")
public void sendToDevice(Message msg, @AuthenticationPrincipal User principal) throws Exception {
    publishMessageToRedis(msg);
}

private void publishMessageToRedis(Message message) throws JsonProcessingException {
    ObjectMapper objectMapper = new ObjectMapper();
    String messageString = objectMapper.writeValueAsString(message);
    stringRedisTemplate.convertAndSend("message", messageString);

}   

redis config

@Bean
RedisMessageListenerContainer container( MessageListenerAdapter chatMessageListenerAdapter) throws URISyntaxException {

    RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    container.setConnectionFactory(connectionFactory());
    container.addMessageListener(chatMessageListenerAdapter,  new PatternTopic("message"));
    return container;
}

@Bean("chatMessageListenerAdapter")
MessageListenerAdapter chatMessageListenerAdapter(RedisReceiver redisReceiver) {
    return new MessageListenerAdapter(redisReceiver, "receiveChatMessage");
}

public class RedisReceiver {
    private static final Logger LOG = LogManager.getLogger(RedisReceiver.class);
    private final WebSocketMessageService webSocketMessageService;

    @Autowired
    public RedisReceiver(WebSocketMessageService webSocketMessageService) {
        this.webSocketMessageService = webSocketMessageService;
    }

    // Invoked when message is publish to "chat" channel
    public void receiveChatMessage(String messageStr) throws IOException {

        ObjectMapper objectMapper = new ObjectMapper();
        Message message = objectMapper.readValue(messageStr, Message.class);
        webSocketMessageService.sendChatMessage(message);

    }

}

@Service
public class WebSocketMessageService {

    private final SimpMessagingTemplate template;
    private static final Logger LOG = LogManager.getLogger(WebSocketMessageService.class);

    public WebSocketMessageService(SimpMessagingTemplate template) {

        this.template = template;
    }

    public void sendChatMessage(Message message) {
        template.convertAndSendToUser(message.getTo(), "/secured/topic", message);
    }

}

Решение основано на этом git-репозитории

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...