Creating a Real-time Buddy List with Advanced Channel Groups
In this tutorial, we’ll cover advanced channel groups, and show you how to build efficient real-time buddy lists (ie. friend lists) for web and mobile chat applications. The buddy list monitors user status, and updates based on any changes in online/offline status in real time.
What are Channel Groups?
The essential feature required to implement this functionality is the “Channel Group” feature, which can also be thought of as a “Subscribe Group.” The first concept to understand is what a Channel Group does. It groups channels into a persistent collection of channels that you can modify dynamically, and it allows you to subscribe to all these channels by simply subscribing to the group.
On the PubNub server side, all published messages and presence events are aggregated for all channels in the channel group. What this means is that if you subscribe to the Channel Group, you get all messages from all the channels in the group in a single stream, if you subscribe to the presence events of the Channel Group, you get all the presence events for all the channels in the channel group in a single stream.
It’s this multiplexing magic that allows for creating Friend Lists and Status Feeds.
All Presence features use the UUID that is set on PubNub client initialization for tracking of that client, which typically is the user. While it’s called a UUID, it doesn’t have to follow the standard UUID format at all, it’s a freeform string. The only real requirement (also not enforced), is that it’s unique.
It’s recommended to actually combine a unique identifier with the platform as well for instance:
This way, not only do you track the user because you can see the uuid, but if the user is also using multiple platforms, you can see that too.
If you don’t supply your own UUID to PubNub init, one will be generated, but it may not be reused or saved (depending on the platform), so you will want to set your own. Again, it can follow any format you want.
In the case of the examples below, for readability, I am just going to use User A, User B, etc. and follow a convention of
ch-user-a-[xyz] for channels, and
cg-user-a-[xyz] for channel groups.
Every user will need two channels: 1) a channel they publish to for their own status messages, 2) a channel they subscribe to to indicate they are online. They will be unique for each user. For convenience, we will use user-[letter], like user-a or user-b, as the unique identifier.
We will follow this naming convention:
- ch-user-a-status (publish)
- ch-user-a-present (subscribe)
These channels will be added into Channel Groups to enable the monitoring and aggregation of both status messages into a Feed, as well as presence for online status. It’s not required to do both if you only want to support Friend Lists/Presence or you only want to support Status Feeds.
User Channel Groups
Each user will also have two channel groups: 1) a channel group for observing the online status of friends, 2) a channel group to receive status updates in real time. Again we’ll use the same convention for unique user identifiers.
We will follow this naming convention:
Expanding the Friend graph through friending is very straightforward: You are simply adding channels to channel groups! In the case of User A and User B becoming friends, you are adding the “present” channel to each users’ friends group, and adding the “status” channel to each users’ status-feed group.
Now to see these working, it comes to how you subscribe. What’s a bit different here is that you will subscribe to one group for messages (status-feed) but subscribe to the other groups’s Presence Event channel for the online/offline status (friends).
Friends Online/Offline (Presence)
For Presence, we track the subscribers on a channel, and we create a sister channel based on the channel name for all the Presence Events on the main channel. This sister channel is simple the channel name + “-pnpres”. So for channel
ch-user-a-present, the sister channel is
ch-user-a-present-pnpres and that’s where PubNub publishes Presence Events that occur on
ch-user-a-present. The Presence Events are as follows:
- JOIN – client subscribed
- LEAVE – client unsubscribed
- TIMEOUT – client disconnected without unsubscribing after timeout period
- STATE-CHANGE – client changed the contents of the state object
And for each event, we also include the UUID and the channel occupancy (how many subscribers).
To see your friends online/offline status and be updated in real time, you subscribe to the friends channel group, but not directly, you subscribe to the Presence Event sister channel only, by appending “-pnpres” to the channel group name.
The reason you don’t want to subscribe directly to the group is because Channel Groups are “Subscribe” groups, and therefore you would inadvertently subscribe to all that users’ friends’ “present” channels! We are only interested in the Presence Events in this group.
Status Feed (Messages)
The status-feed channel group is much more straightforward, you are going to subscribe directly to the channel group and you will receive status updates in real time via each channel in the group.
Since we include the “present” channel for this user in the channel group (
ch-user-a-present), this also has the net effect of subscribing to that channel, it also means it generates a JOIN event for every channel group that includes this user’s present channel. So, if User B is friends with User A, when User A subscribes to this status-feed channel group, it also subscribes to User A’s present channel and generates that JOIN event, as well as all the other Presence events.
NOTE: If you implementing only the Friend List and not the Status Feed, User A will need to subscribe to this
ch-user-a-present channel directly since User A isn’t subscribing to the status feed group which includes this channel.
Simple and powerful buddy lists are fairly easy to do with PubNub! I’d argue it’s even easier than trying to develop a full backend to support the Presence and Status Feeds, and on top of that, it’s real-time. Can’t be beat!
Lastly is retrieving history of status messages can be a bit more work as you have to retrieve messages from each channel in the group individually (each friend) and mash/sort them together client side. I’ll make another post on how to do that, and a little bit of code that can handle it at least semi-auto-magically.
For every decision there is a counter-decision, and for every idea there is a more complex version. I’ll throw in a few caveats to this implementation, there are some interesting ways of changing Status Feeds that can make things a bit trickier, one is “weighting” the status message, so that it’s no longer chronological, but rather based on interests, or activity, or other things. Another layer of complexity that you can add is commenting on status items.
Again, it requires a bit more logic here, and it might not be the simplest thing to do, but it depends on how you want it to work. It’s certainly quite possible, but not quite as easy as the above.