ActionCable - как отображать число подключенных пользователей?

Я пытаюсь создать простое чат-приложение (планирование приложения для покера) с помощью Action Cable. Я немного смущен терминологией, иерархией файлов и тем, как работают обратные вызовы.

Это действие, которое создает сеанс пользователя:

class SessionsController < ApplicationController
  def create
    cookies.signed[:username] = params[:session][:username]
    redirect_to votes_path
  end
end

Затем пользователь может опубликовать голосование, которое должно транслироваться всем:

class VotesController < ApplicationController
  def create
    ActionCable.server.broadcast 'poker',
                                 vote: params[:vote][:body],
                                 username: cookies.signed[:username]
    head :ok
  end
end

До сих пор все ясно для меня и прекрасно работает. Проблема заключается в следующем: как отобразить количество подключенных пользователей? Есть ли обратный вызов, который срабатывает в JS, когда пользователь (потребитель?) Подключается? Я хочу, когда я открываю 3 вкладки в 3 разных браузерах в режиме инкогнито, я бы хотел отобразить "3". Когда новый пользователь подключается, я хотел бы, чтобы число увеличивалось. Если какой-либо пользователь отключается, число должно уменьшаться.

Мой PokerChannel:

class PokerChannel < ApplicationCable::Channel
  def subscribed
    stream_from 'poker'
  end
end

app/assets/javascripts/poker.coffee:

App.poker = App.cable.subscriptions.create 'PokerChannel',

  received: (data) ->
    $('#votes').append @renderMessage(data)

  renderMessage: (data) ->
    "<p><b>[#{data.username}]:</b> #{data.vote}</p>"

Ответ 1

Кажется, что один способ использовать

ActionCable.server.connections.length

Ответ 2

Для быстрого (и, вероятно, не идеального) решения вы можете написать модуль, который отслеживает подсчет подписей (используя Redis для хранения данных):

#app/lib/subscriber_tracker.rb
module SubscriberTracker
  #add a subscriber to a Chat rooms channel 
  def self.add_sub(room)
    count = sub_count(room)
    $redis.set(room, count + 1)
  end

  def self.remove_sub(room)
    count = sub_count(room)
    if count == 1
      $redis.del(room)
    else
      $redis.set(room, count - 1)
    end
  end

  def self.sub_count(room)
    $redis.get(room).to_i
  end
end

И обновите подписанные и отмененные подписки методы в классе канала:

class ChatRoomsChannel < ApplicationCable::Channel  
  def subscribed
     SubscriberTracker.add_sub params['room_id']
  end

  def unsubscribed
     SubscriberTracker.remove_sub params['chat_room_id'] 
  end
end

Ответ 3

В связанном вопросе о том, кто связан, был ответ для тех, кто использует redis:

Redis.new.pubsub("channels", "action_cable/*")

и если вы просто хотите количество соединений:

Redis.new.pubsub("NUMPAT", "action_cable/*")

Это приведет к обобщению соединений со всех ваших серверов.

Все магия покрыта в классе RemoteConnections и модуле InternalChannel.

TL; DR все соединения подключаются по специальным каналам с префиксом action_cable/* с целью отключения сокетов от основного рельса.