We had a social application without a chat, 2 weeks to develop it, and absolutely no knowledge of existing protocols for implementing IM. Not that it was the necessary set to shoot himself in the foot, but in the process, it happened. Repeatedly.
- Pasha, we need to make a chat.
- Yes, everything is simple, my friends here used XMPP to chat in their application.
What were our requirements? Nothing special, simple messaging between users, without group conversations. Platforms: web (with support for working via web sockets), Android, iOS. Creating users should automatically be done only by our server application. Of course, it would be nice to have marks on whether the message was read or not (it is assumed that the application can be used from different devices), and to be able to view the chat log. In general, the standard functionality for instant messaging in 2015. Bonus points are awarded if the server can scale horizontally.
Hmmm sounds tempting. We google comparison with other standards, we open the
link to article in Wikipedia . First thought: Wow, cool, there is everything we need.
')
Why did we choose XMPP?
- XMPP is an open protocol developed by the XSF (XMPP Standards Foundation), an independent non-profit organization. These guys must be pretty smart and have foreseen everything the messaging protocol needs (yeah, of course).
- Since the open protocol must have quite a few server implementations, and at least one of them will be good enough to use it.
- For the same reason, for each of the programming languages there will certainly be 1-2 libraries.
- The first letter X in the abbreviation means extensible, extensible. Even if we do not like something in the protocol, we can always expand with our own methods.
Protocol
The guys who developed the protocol really provided a lot. For example, take a look at the
message archiving design . Individual archiving settings for sessions. Description of what to do if one of the users wants his messages not to be stored on the server, and the second wants it. At the same time, there is no normal mechanism for receiving archive of messages by pages. By normal, I mean offset and limit. Here you can set only the max parameter, which will set the maximum number of messages and the start parameter, which means the time from which you will receive messages.
Or, for example: the protocol does not define what should be done with offline messages (messages sent to the user off-line). Therefore, most servers simply send them to the user at the next login. Remember the requirement that the user can use the application from multiple devices? So, if you run the application on your smartphone, and then enter the web application, all offline messages will come to your smartphone and ... everything. That is, you can’t find out about it in a web application. It is worth noting that some servers behave differently, that is, they implement
XEP-0013 .
Oh yeah, the protocol for IM (instant messaging) in 2015 does not have a specification that would allow you to get a list of unread messages and mark some of them as read. Totally.
Implementations
At the very beginning, I did not know what problems from the previous paragraph I would have to face, and therefore MongooseIM was chosen as the server implementation. Scalable, can prohibit permission to register only from certain ip, supports web sockets. For the front-end web, the JSJaC library was chosen because it provided a more convenient API compared to strophe.js. A simple page from the examples of JSJaC connected to the server from a half-kick, and my joy knew no bounds. It would seem that the work is finished. Almost.
And then I ran into the last voiced problem from the previous paragraph. Since the protocol does not imply the possibility to receive unread messages, and in general it doesn’t mean that the messages are read / unread, this part of the functionality will have to be added. Being not strong at erlang programming, I began to look for other suitable server implementations. I was looking for Java or JavaScript implementations.
Openfire is one of the most popular implementations of XMPP in Java. The advantages include ease of setup: everything happens through the web interface. Further only minuses: requirements to resources, lack of a plug-in for work through web sockets.
The only thing worth mentioning from JavaScript projects was
xmpp-ftw . The project implements many extensions from XMPP. However, its use had to be abandoned, since we would not be able to use existing client libraries. Maybe it would not be so good with him.
Tigase at first seemed a salvation. Fast, scalable server in Java, with the ability to write a plugin and quite simple to connect it. And the lack of documentation. Instead, it was recommended to read the source code. But this is nothing, I already do that more often. I wrote a plugin that flagged new messages unread. In order to register users, we had to write them directly to the database, because the administration API could not be properly used. Fortunately, Tigase has a driver for connecting to Mongodb. Receiving unread messages was done by a separate application API method (the crutch could have been done by the plug-in inside Tigase, but it would take much more time, because a rather low-level API is used to communicate with the DBMS inside Tigase). By connecting everything I checked - until the message is marked read (by the way, messages do not have an id in xmpp, so it was decided to mark the read all the correspondence with a specific user) it is returned in the unread list. Everything is working. It remains to check only the case with offline message. Yes, it was not marked unread, because the plugin that processes offline messages is triggered earlier than archiving. On the Tigase forum, the developer responded that the behavior I needed was implemented in the commercial project Tigase Unified Archive. Googling by its name did not lead to anything, the developer on the forum said that the project is still unstable and there is no release version. Having rummaged in source codes of the server found that it is possible to receive the necessary behavior having exposed to all messages the chat type.
Now let's go through the client implementations. Let's start with JavaScript implementations. We tried only JSJaC, which was eventually changed to strophe.js. The first has a more pleasant API, but it has only basic functionality, not supporting work with extensions, for example, with the archive. At the same time, strophe instead offers a rather convenient xml builder. Well, to abstract from interiors XMPP did not work. By the way, the web socket connector in JSJaC works only in Webkit.
From Java clients only Smack is currently tried. If an invalid packet is sent, NoResponseException will most likely be thrown, and that’s all you will know.
Conclusion
Maybe my problem is that I hoped that someone solved some of my problems for me and did it well. If I knew all this first, I would suggest to write my own chat server. Seriously. The point is not that the protocol is bad or not suitable for use in implementing IM with modern requirements, although I still think so. Simply, I would prefer to have my own code and lay the necessary opportunities for expansion, rather than shovel so many other people's code and specifications. XMPP is quite successfully used to solve a huge range of tasks for which, it seems, it is well suited. Although most solutions use only basic functionality.