Presence and how to track several groups of users

phoenix
presence
phoenix_pubsub

#1

Hello,

I am currently busy with my first real app using elixir/phoenix and react (backend communication using sockets/channels only except for one REST endpoint for error messages). So far it has been a enjoyable ride.

It is a kind of a multiplayer interaction environment where users log in with a PIN and pick a nickname. Using a given PIN, a nickname must be unique/not chosen yet in order be able to connect. And through the PIN, the application does know which content to display. And basically all connected nicknames for a given PIN form a group of users interacting (interaction happens through one or more channels).

In order to achieve the “only one socket connection for a given PIN and nickname”, I have implemented a presence check within the socket connect and tracking of the socket process through Presence.track/4 using the socket pid as pid, the module name (of the socket) as topic and the nickname as key.
The socket Presence.connect/2 code basically does a Presence.list/1 and checks if the user provided nickname is present within the presence list, returning :error to not allow the connection in case the nickname is present.

This works so far for one PIN. But in the future I would have to allow more than one PIN to be used (within the same application deployment). I also would like to inform some separate gen_server that some presence changes happened.

I guess I could use the PIN as a topic or combine the PIN and the nickname together to form the key for tracking and validation but it seems that it does not solve the presence change tracking. Then there is the subscribe functionality in pubsub which might help (subscribing on “phx_presence:Elixir.MyApp.Presence” or something like that)?
Or should I explore custom trackers and save the presence data into an agent/gen_server of some kind (no idea yet how to do that though) maybe?

Any thoughts would be very much appreciated :slight_smile:

Best regards


#2

I can’t answer all of your questions but I would steer you towards the creating a channel for each pin. And you can keep using Presence.list/1 on socket connect to verify that the currently selected username is not connected with the pin. With this approach you shouldn’t need to call Presence.track/4 manually for this “authentication” piece.

For this I think you may be able to use Presence.track/4 or similar from the gen_server (although I haven’t tried this myself). But it depends on the type of processing that you want to do in this gen_server. If you don’t need to share state between “PIN”'s then you may want to use one gen_server per PIN.