4

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?

Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382

3 Answers3

2

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. :-)

Kirk Strauser
  • 30,189
  • 5
  • 49
  • 65
  • Neat! Referenced in my answer to [this question](http://stackoverflow.com/questions/12607317), maybe you have some useful details to add? :) – Lukas Graf Sep 26 '12 at 18:47
1

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: 'groupchatroom@conference.demo.com/' + 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.

Gjorgji Tashkovski
  • 1,948
  • 1
  • 13
  • 14
  • Hi Gjorgji. You're right. Using presence stanzas would the be the best solution. Could you look at my edit please. Thanks. – Mridang Agarwalla Jul 05 '11 at 21:07
  • You need a bot for each MUC room. As soon as the visitor joins the room, use connect method of Strophe `connection.connect( jid, password, onConnect);` and in onConnect function, send message to the room (presence). The bot will receive the stanza and forward it (maybe modified, message stanza) to the support personnel. So, they'll know which room the visitor has joined. – Gjorgji Tashkovski Jul 05 '11 at 22:11
  • Gjorgji, do you know if it's possible to send presence notifications to other users on the server i.e. all the sales/support people like `salessupportguy*_site_1@demo.com`. (* is the wildcard). The visitor wont have all the sales/support people on the roster though. – Mridang Agarwalla Jul 06 '11 at 09:35
  • See my edited answer. You should consider also sending message stanza to the bot in the MUC room alerting him that someone has joined the conversation. All your questions are answered in http://professionalxmpp.com which I highly recomend. – Gjorgji Tashkovski Jul 07 '11 at 06:53
1

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.

Mike M.
  • 543
  • 4
  • 13
  • Hi Mike. I didn't quite follow. I'm quite new to this whole thing so I'm very lost. When the visitor begins to type, it makes an AJAX request to DB? Thanks a lot. – Mridang Agarwalla Jul 05 '11 at 19:15
  • Hey Mridang. You can use an IQ stanza (XMPP version of a request/response) to send the notification over BOSH. Strophe provides the interface to do this. You should take a look at XEP-0060 Pubsub, as it may contain some useful info for you. Also, new users should be able to send a directed presence (basically presence stanza with a 'to' attribute) message to your bot, even if they are not on the bot's roster. This way the bot will know the presence of users. – Mike M. Jul 06 '11 at 02:58
  • Hi Mike. I'm sort of getting the whole idea now but I'm trying to eliminate the bot. It's a kludgy implementation. I made an eit to my post yesterday and I don't know if you've seen it. Please have a look at the second part. When the user logs on, i could send a presence to all the sales/support people, but they would need to be on the visitor's roster right? How can i do this? Would this work? – Mridang Agarwalla Jul 06 '11 at 06:59
  • I still think you could do this with pubsub. The users could all publish to a common node, and the support people could be subscribed to it. Then, when a user logs in, the support person's client would be notified. Their client would then make the connection to the chat room, or you could just have them initiate a regular IM session with the user. Also, you could have a separate node for each site_id, thus separating the sites further. – Mike M. Jul 07 '11 at 04:40
  • Also, if all your JIDs are known ahead of time you could setup the rosters in the server's database. That way, when a user connects their roster is all ready to go. Roster subscriptions can be of type 'to', 'from', or 'both', so you can prevent the users from receiving presence from all the support personel, but could allow the support personel to see all the logged in users. Like I said though, this will only work if you can setup the rosters ahead of time. – Mike M. Jul 07 '11 at 04:44