Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActionCable - how to display number of connected users?

I'm trying to create a simple chat-like application (planning poker app) with Action Cable. I'm a little bit confused by the terminology, files hierarchy and how the callbacks work.

This is the action that creates user session:

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

A user can then post a vote that should be broadcasted to everyone:

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

Up to this point everything is clear for me and works fine. The problem is - how do I display the number of connected users? Is there a callback that fires in JS when a user (consumer?) connects? What I want is when I open 3 tabs in 3 different browsers in incognito mode I would like to display "3". When a new user connects, I would like the number to increment. If any user disconnects, the number should decrement.

My 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>"
like image 962
pmichna Avatar asked Oct 02 '15 10:10

pmichna


3 Answers

Seems that one way is to use

ActionCable.server.connections.length

(See caveats in the comments)

like image 130
pmichna Avatar answered Oct 31 '22 16:10

pmichna


For a quick (and probably not ideal) solution you can write a module that tracks subscription counts (using Redis to store data):

#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

And update your subscribed and unsubscribed methods in the channel class:

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

  def unsubscribed
     SubscriberTracker.remove_sub params['chat_room_id'] 
  end
end
like image 31
T1000 Avatar answered Oct 31 '22 14:10

T1000


In a related question on who is connected, there was an answer for those who uses redis:

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

and if you just want number of connections:

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

This will summarize connections from all your servers.

All the magic covered inside RemoteConnections class and InternalChannel module.

TL;DR all connections subscibed on special channels with a prefix action_cable/* with only purpose of disconnecting sockets from main rails app.

like image 3
Алексей Лещук Avatar answered Oct 31 '22 15:10

Алексей Лещук