This is a continuation of a series about a real-time communications app we are building with one of our customers.
Features for managing conversations
Since we had chosen XMPP as our communication platform, initially, we planned to use facilities built into that protocol. XMPP at its core is all about Presence (tracking whether someone is online or offline, available or away) and Messaging (allowing John to talk to Jane). Through many extensions known as XEPs, XMPP has been extended to support many more things, such a group messaging (chat rooms), contact information (VCard), multi-device message replication (Carbons), and chat bookmarks. With tools like Hipchat and Slack setting the bar so high for usability, it was important that we match several fundamental features. For example, if a user is on his phone and chatting, and then switches to his desktop, we wanted to carry across all active conversations, and do so in real time. Thus, sending a message from his phone would appear instantaneously on his desktop, and vice versa.
Finding someone to talk to
As described in a previous post, one of the early issues we hit was that of managing the user’s roster, sometimes called a “buddy list.” XMPP does permit grouping contacts, and our server of choice, ejabberd, has a plugin for reading that group data from LDAP. Our problem was that flat groups don’t really impart enough information. When I may want to speak with any one of 1,000 people, search plays a much more important role. As the tool evolved, we started drifting away from using roster groups and toward a global search. The most common case was that users want to find each other by name. When showing results, it can be helpful to show the titles, departments and locations of search results. This is especially helpful when you have two “Chris Jones” and you want the one that works in Finance. Unfortunately, we could not find a way to do this via XMPP alone. In the end, we continued to use XMPP’s roster to track availability, but provided the names and metadata via an HTTP API.
Keeping track of active conversations
Another requirement that came up was the ability to store and retrieve a list of active chats (whether open rooms or active one-on-one conversations). XEP-0058 specifies how clients may store a list of open chat rooms using PEP, or Personal Eventing Protocol. However, PEP has three limitations that were critical for us:
- PEP is designed to be managed over XMPP, making that information difficult or impossible to display and manage via our web interface
- XEP-0058 only specifies MUC room bookmarks, not one-on-one chats
- The standard does not do anything to preserve bookmark order
This left us with two options. First, we could create our own proprietary extension to XEP-0058 and fix these issues. Doing so would be non-standard, and even then would not resolve the first issue. The second option, and the one we chose, was to use an HTTP API to store bookmarks in our web application. Then we modified our clients to use the API for bookmarks and stopped storing them in ejabberd.
Can I get your number?
When talking to someone, it’s often helpful to see some context such as a title, department, or even a photo. Within our application, we have different security levels, where some users can see semi-private details such as mobile phone number or home address, while others can only see the title and territory. While there are a few XEPs available for storing and retrieving the contact information, they too fell short in a few ways:
- There are at least three relevant standards, two of which are historical, which suggests the standard mechanism for storing this information is still evolving
- More importantly for us, VCard in XMPP is all-or-nothing; we have no way of instructing the XMPP server which subset of VCard information should be shared to a given requesting user
Once again, we found ourselves in the position of being forced to route requests for this information via an HTTP API. Using our web application to serve the information meant that we could customize the view for each requestor, taking into account things such as the requestor’s role and privileges.
So, what have we learned?
In each of the problems above, we found ourselves compelled to work around XMPP, rather than use its facilities. I want to recognize that in each of the above cases, we could have also solved the problem by modifying the XMPP server itself. In fact, had the application requirements been different, we likely would have done just that. In this case, the tool only has two clients, both of which are being developed internally. Given that luxury of control over the client, ultimately, we made the determination that the more cost effective route was to use our web application to store and manage the information. In cases where open standards and federation are more important, we probably would reach a different conclusion. In the end, there is almost always more than one way to do it. Understanding the requirements, resources available, and desired user outcomes will lead you to the best path for your application.