Трансляция только в один веб-сокет в комнате с помощью ActionCable - PullRequest
0 голосов
/ 18 февраля 2019

Я использую ActionCable для предоставления уведомления браузера, который легко реализовать.Проблема возникает, когда пользователь открыл несколько вкладок в браузере, и мне нужно отправить данные только на одну вкладку, т.е. только на один WebSocket в комнате пользователя.Как это можно сделать?

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Каждый раз, когда устанавливается новое соединение, мы создаем новую комнату.Так, например, когда пользователь устанавливает новое соединение, мы можем дать имя комнаты как users: user_id: some_unique_random_string, которое может быть равно users: user_id: 123j123b1h2b1j23bh12b3, и когда тот же пользователь устанавливает другое соединение, открыв другую вкладку, мы также сделаемто же самое и создать отдельную комнату.Теперь одна вещь, которую обеспечивает ActionCable, состоит в том, что мы можем найти все имя комнаты, за которым следует любой префикс.

Позволяет пользователю выполнить три подключения, и его комнаты являются пользователями: 128: 123n1jh123ko9876, пользователи: 128: asdas23412cs1234, пользователи: 128: asni9202h5i3jens, затем мы можем получить имя этой комнаты также с помощью ActionCable.

user_id = 128
pubsub = ActionCable.server.pubsub
channel_with_prefix = pubsub.send(:channel_with_prefix, RoomChannel.channel_name)
channels = pubsub.send(:redis_connection).pubsub('channels', "#{channel_with_prefix}:users:#{user_id}:*")

Теперь каналы - это массив, состоящий из имени комнаты.

Итак puts channels

["chatapp_production:users:128:123n1jh123ko9876", "chatapp_production:users:128:asdas23412cs1234", "users:128:asni9202h5i3jens"]

Так мы можем найти все комнаты, относящиеся к одному пользователю, безиспользуя любую внешнюю базу данных и вызовы API.

0 голосов
/ 20 февраля 2019

Изоляция одного клиента pub / sub напрямую невозможна при использовании подхода pub / sub, поскольку вся идея заключается в том, что издатели не знают о подписчиках.

Однако существует два распространенных способа решения проблемы.this:

  1. для использования другого именованного канала для каждого соединения, сохранения именованного канала в базе данных и пересылки всех сообщений на этот конкретный именованный канал (т.е. сохранения канала user-ID-TIMESTAMP в базе данныхи используя его в качестве целевого соединения).

  2. другой, несколько более надежный (хотя и более сложный) подход - отправить сообщение всем клиентам, но создать условие гонки, которое допускает только одноклиент для получения актуального сообщения.Это будет выглядеть примерно так:

    • сервер отправляет "у вас есть сообщение" всем клиентам.
    • клиент опрашивает "недоставленные" сообщения с сервера.
    • Сервер блокирует пул сообщений или использует транзакцию базы данных для извлечения недоставленных сообщений и пометки сообщений как доставленных.Сервер отправляет недоставленные сообщения клиенту (опционально устанавливая таймаут ACK).
    • одно клиентское соединение получает недоставленные сообщения, остальные получают пустой массив сообщений (поскольку все они были доставлены другому клиенту)или получите флаг «доставлено», чтобы данные обновлялись, но уведомление не выдавалось.
    • (необязательно), клиент отправляет и ACK.
    • (необязательно) сервер помечает доставку сообщения как завершенную,Если ACK не был получен до истечения времени ожидания, сервер снимает пометку с доставки и отправляет сообщение «У вас есть сообщение».

Удачи!

...