Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

presence channel + multiple tabs #96

Closed
robj opened this Issue · 6 comments

2 participants

@robj

If a user enters a presence channel multiple times (eg. multiple tabs), closing just one of those tabs fires a 'member_removed'.

This is not the behaviour when using Pusher, ie.

http://pusher.com/docs/client_api_guide/client_presence_channels

pusher:member_removed
The pusher:member_removed is triggered when a user leaves a channel. It's quite possible that a user can have multiple connections to the same channel (for example by having multiple browser tabs open) and in this case the events will only be triggered when the last one is closed.

@stevegraham
Owner

we're aware of how pusher treats multiple connections to the same presence channel from the same user. slanger handles this the same way. i checked using the example apps and pusher:member_removed is only fired when the last connection is closed.

how are you producing this behaviour. if there is something amiss, of course i am happy to fix it.

@robj

I tracked down the cause of the issue as follows:

Slanger requires the user_info hash to stay consistent, whereas Pusher.com does not.

ie. I have this in my PusherController auth action

    :user_info => { # => optional - for example
      :id => current_user.id, #repeat as easier to pass hash to backbone/roster template
      :name => current_user.name,
      :joined_at => Time.now,
      :profile_image_small => current_user.profile_image_small,
    }

'joined_at' is used to render a roster client side sorted in order that the user joined the channel ( just to make sure I also tested adding :random => SecureRandom.hex(4) to the hash, and it had the same effect )

If the user hash differs then multiple member_added/member_removed events are triggered in a presence channel when opening/closing multiple tabs/windows.

@stevegraham
Owner

i see. how pusher determines if a user is new or the same as the another is unspecified in pusher's docs. this was an assumption i made when writing the code, not seeing the use case for the same user having multiple connections with non-identical user info objects. the code you're looking for is probably https://github.com/stevegraham/slanger/blob/master/lib/slanger/presence_channel.rb#L118

i'll get to this in time, but you're more than welcome to contribute a fix yourself. if you want to do that, please discuss how you intend to implement your fix with @markburns and me beforehand, in order to ensure it can be merged with minimum friction.

@robj

I imagine there is a more concise way, but I have used the following code:

def user_subscribed?(subscriptions,channel_data)

  subscriptions.each do |sub|


     if sub[1]['user_id'] == channel_data['user_id']
       return true 
     end

  end

  false

end

....

   #unless subscriptions.has_value? message['channel_data']
   unless user_subscribed?(subscriptions,message['channel_data'])

...

    #unless subscriptions.has_value? subscriber
    unless user_subscribed?(subscriptions,subscriber)
@stevegraham
Owner

Subscriptions is a method so it doesn't need to be passed in as an argument. Try this:

def user_subscribed?(channel_data)
  subscriptions.any? do |_,user_info|
    user_info['user_id'] == channel_data['user_id']
  end
end
@robj

great, thats a better way for sure, tested and working, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.