4
votes

I need to implement an XMPP based live-chat system in Django. After a lot of scourging and ideas from a colleague, we came up with this.


Method using a bot:

  • When a visitor visits the site. The visitor's XMPP client which in this case is Strophe.JS begins an XMPP-over-BOSH connection to the XMPP server and connects to a room called <visitor_id>@conference.demo.com. Currently there is no one else in the room.
  • The visitor makes an analytics request with a custom visitor id to Django
  • The Django view, stores the visitor id in a table called ActiveUsers. This table contains a new field as well called status. It sets the status to INACTIVE.
  • This model dispatches a signal on the save method.
  • This signal gets picked up by a bot which connects to the XMPP server and joins the room <visitor_id>@conference.demo.com. Now we have the user and the bot in the room.
  • The site support people are logged into their web interface.
  • They have JS code that keeps long-polling the Django site to check the ActiveUsers. It fetches the rows from the table and displays it. (I've thought of using django-pubsub for this)
  • When the visitor types a message, it goes via XMPP-over-BOSH to the XMPP server, the jabber bot in the room see this message and updates the status of the record in the ActiveUsers table to ACTIVE.
  • As said: The site support people have JS which keeps polling this table. It begins blinking the ow to show that the user is now chatting.
  • The support personnel can now double-click that row which on doing so begins an XMPP-over-BOSH connection to the visitor's room. It knows that the room is <visitor_id>@conference.demo.com.
  • The bot seeing that the support person has joined the room, updates ActiveUsers record to show CHATTING. This ensures that no more than support personnel can be in the room i.e. room occupied.
  • The bot logs the messages to a Django table
  • When the both sees that both users have left the room, it deletes the record.

ejabberd or openfire will be XMPP server. Apache is the web server which runs mod_wsgi for serving Django and mod_proxy for proxying the XMPP-over-BOSh requests to the XMPP server.

Does this sound like a good of doing this? Any suggestions? I'm worried about the load on the Django system.

(It's long. Sorry 'bout that.)


Method using Presence Stanzas:

On the client side, i'm using Strophe JS library which supports presence and I had add callback methods. I'm flexible with using ejabberd or openfire as my XMPP server. The are many visitors on the XMPP server — some from site A and some from site B but they are all connected to the same XMPP server. When the visitor visits the site, they are connected to the XMPP server as <visitor_id>_<site_id>@demo.com and each one gets logged into a room called <visitor_id>@conference.demo.com. The sales/support personnel are also connected to the XMPP sever as <supportsale_id>_<site_id>@demo.com. They are not connected to any chat room though. They don't have any of the visitors on their roster.

A good way of showing that a user has connected to the site would be to pass a presence stanza to the sales/support people. Only visitors and sale/support personnel from the same site communicate with each other and that's why I have the <site_id> in the username to show which site that person belongs to.

It seems that you can't subscribe to presence stanzas for a user if you don't have him on your roster. (Quite logical). Is is possible to automatically add every new user of a site connecting to the system to the roster of the sales/support people of that site? Wouldn't this then automatically signal a presence to the sales/support people? How can I implement this — any help?

3

3 Answers

2
votes

I wrote exactly this. It's called Seshat and uses a "broker" bot between the website and a Jabber server (I use ejabberd). It's in beta right now mainly because it hasn't been extensively tested outside my company.

Note: while the README specifically mentions the Pyramid web framework, the core system would work just as well with a Django, TurboGears, or command line system. It's just that I only package example code showing how to integrate it with Pyramid.

Seshat is being actively developed. If you have any feature requests, let me know. :-)

1
votes

I'm not sure you need to use MUCs to implement this. Your bot could maintain its own pubsub node which it is subscribed to. When a new user begins to type it could send a notification to the pubsub node, which the bot would then see. From there, the bot could notify a support person via XMPP, thus eliminating the need to long poll the database table. Then the support person could start a standard one to one chat session with the end user. In addition, their presence could be set to 'na' in order to show that they are in a session with a user.

1
votes

I think that it's better to use presence stanzas to "signal" any (in)activity. What you need to store in database is only the persistent data you need for further analysis. Otherwise, I think you'll have great time coding the application :).

EDIT:

function onConnect(status) {
  if (status == Strophe.Status.CONNECTED) {
    var joined = false;
    var participants = {};
    $('#events').html('<text class="textmainleft">XMPP connection established. Ready to rock n roll!</text>');
    connection.send($pres().c('priority').t('-1'));
    connection.addHandler(notifyUser, null, 'message', 'groupchat', null, null);
    connection.send($pres({to: '[email protected]/' + nickname}).c('x', {xmlns: 'http://jabber.org/protocol/muc'}));
  } else if (status == Strophe.Status.AUTHFAIL) {
    $(location).attr('href', AUTHFAIL_URL);
  } else if (status == Strophe.Status.CONNFAIL) {
    $(location).attr('href', AUTHFAIL_URL);
  }
}

$(document).ready(function () {
  connection = new Strophe.Connection(BOSH_SERVICE);
  connection.connect(jid, password, onConnect);
});

notifyUser is another function (just link onConnect) that would handle the received message stanzas.