An XMPP Echo Bot With Twisted And Wokkel
September 25, 2008
Twisted is one of the best ways to write XMPP software, but it is pretty poorly documented. It’s gotten even better with Ralph Meijer’s work on Wokkel, which extends Twisted’s XMPP support with subprotocols and other goodies. To show you just how easy Twisted and Wokkel make things, here is a simple echo bot.
Getting the things you need will probably take longer than writing the code. Luckily, your second project with Wokkel will materialize much faster.
- Twisted 8.x. This is included in most Linux distributions our you can get it from Twisted Python’s Web site.
- Wokkel. Grab the latest from the repository.
Once these are installed or in your Python path, you can proceed to the actual code.
An Echo Bot Sub-protocol
Our echo bot will speak a custom sub-protocol of XMPP. It will listen for any message stanzas and then reply to some of them. We’ll put this code in
from twisted.words.xish import domish from wokkel.xmppim import MessageProtocol, AvailablePresence class EchoBotProtocol(MessageProtocol): def connectionMade(self): print "Connected!" # send initial presence self.send(AvailablePresence()) def connectionLost(self, reason): print "Disconnected!" def onMessage(self, msg): print str(msg) if msg["type"] == 'chat' and hasattr(msg, "body"): reply = domish.Element((None, "message")) reply["to"] = msg["from"] reply["from"] = msg["to"] reply["type"] = 'chat' reply.addElement("body", content="echo: " + str(msg.body)) self.send(reply)
Some things to note about this code. A
MessageProtocol simply looks for messages and calls
onMessage when one is received.
MessageProtocol inherits from
XMPPHandler which is the base class for all sub-protocols.
XMPPHandler will call
connectionLost on connect and disconnect, just like other Twisted protocol classes.
All the connection details and authentication are handled by the
XMPPClient service, which we will see next.
Twisted includes an application runner called
twistd which takes a
.tac file as input. The tac file sets up the various services that compose the application and manages their life cycle. It takes care of making things a daemon, handling PID files, and many other tasks common to applications.
from twisted.application import service from twisted.words.protocols.jabber import jid from wokkel.client import XMPPClient from echobot import EchoBotProtocol application = service.Application("echobot") xmppclient = XMPPClient(jid.internJID("firstname.lastname@example.org/echobot"), "pass") xmppclient.logTraffic = False echobot = EchoBotProtocol() echobot.setHandlerParent(xmppclient) xmppclient.setServiceParent(application)
Be sure to replace ‘email@example.com’ and ‘pass’ with a real JID and its password. The echo bot application can now be started with
twistd -ny echobot.tac or
twistd -y echobot.tac if you want to daemonize it. Once it is running, go ahead and send it a message!
Every tac file must defines the application variable. Usually you’ll create some services for the application and then use
setServiceParent to make them part of the application. For
XMPPClient services, we have to use a similar method to activate our sub-protocol handler; we call
setHandlerParent to make our sub-protocol part of the
Building sub-protocols is pretty straight forward. You can look at the MessageProtocol code for an example; it is less than 30 lines including blank lines and comments. Generally XPath expressions are set up to listen for particular stanzas, and these call specific handlers when the stanzas are received.
Wokkel also contains a pubsub client protocol and a pubsub service protocol implementation. Making little pubsub daemons should be quite easy with these.
I’m really excited about Wokkel, and hopefully I can write up some more complex tutorials soon.