IOException.de

Icon

Ausgewählter Nerdkram von Informatikstudenten der Uni Ulm

XMPP Multiuser Chat Bot

Multiuser Chats stellen eine gute Möglichkeit dar mit vielen Leuten gleichzeitig zu kommunizieren. Ich selbst nehme regelmäßig über MUCs an Entwicklermeetings teil oder bespreche mit Freunden, was es so zu besprechen gibt. Und natürlich macht chatten auch viel Spaß :-)

Neulich hatten wir während eines solchen Chats die Idee, dass wir doch unseren WG-Server am Chat teilnehmen lassen könnten, damit dieser uns z.B. mit Zitaten aus Fernsehsendungen unterhält oder wir über ihn die Musik in der Wohnung steuern können. Seit wir begonnen haben den ersten MUC-Bot zu implementieren, kommen immer wieder neue Ideen auf, was ein Bot so alles tun könnte. Zum Beispiel als Wörterbuch fungieren oder Kochrezepte fürs Abendessen vorschlagen.

Damit grundlegende Funktionalität nicht für jeden Bot neu geschrieben werden muss, habe ich begonnen ein kleines Framework zu entwickeln, dass sich um den XMPP-Teil des Bots kümmert und häufig benötigte Funktionen realisiert. Das Framework ist in python geschrieben.

Im Folgenden beschreibe ich die Mucbot-Klasse, die einen einfachen Bot darstellt. Um den Eintrag übersichtlich zu halten lasse ich einige Dinge weg, die nicht wesentlich sind. Daher wird der hier gepostete Code nicht lauffähig sein. Für die komplette Version schaut einfach auf github vorbei.

# Der Bot verwendet xmpppy (<http://xmpppy.sourceforge.net/>) um mit einem 
# Jabber-Server zu kommunizieren.
import xmpp

# Wir brauchen Regular Expressions um in empfangenen Nachrichten nach Keywords 
# zu suchen, auf die reagiert werden soll.
import re

# Das time Modul wird verwendet um Verzögerungen einzubauen. Z.B. falls der Bot
# nach einer bestimmten Zeit etwas sagen soll.
import time

# Der Bot erbt von Thread. Er kann also im Hintergrund gestartet werden, während
# das Programm noch etwas anderes tut.
from threading import Thread

class Mucbot(Thread):

# Es ist einiges an Initialisierung notwendig. Der Bot braucht eine Jabber-ID und
# ein dazu gehörendes Passwort, um sich damit am Server anmelden zu können. Da
# es ja ein MUC-Bot ist, braucht er außerdem einen Raum, dem er sich anschließen
# wird. Optional kann man ihm noch einen Namen geben, eine Liste von Zitaten,
# die er gelegentlich zitiert und ein Dictionary mit Keywords auf die er
# reagieren soll mit dazugehörenden Reaktionen. Die Keywords sind dabei als
# Reguläre Ausdrücke gegeben.
    def __init__(self, jid, pwd, room, botname='', roompwd='', quotes=[],
            minwait=-1, maxwait=-1, reactions={}, delay=3):

        # Kein expliziter Botname? -> Verwende die Node der Jabber-ID
        if botname == '':
            botname = jid.getNode()

        # […]
        # hier werden alle übergebenen Parameter in der Mucbot-Instanz
        # gespeichert, um diese später noch verwenden zu können

        # Um Nachrichten schnell nach Schlüsselwörtern durchsuchen zu können
        # werden alle Regulären Ausdrücke compiliert.
        for key in self.reactions.keys():
            self.reactions[re.compile(key)] = self.reactions.pop(key)

        # Jetzt kommt die Verbindung zum Server. Zuerst erstellen wir ein
        # xmpp.Client Objekt und verbinden uns mit dem angegebenen Server.
        self.client = xmpp.Client(jid.getDomain(), debug=[])
        self.client.connect()

        # Um auf ankommende Nachrichten reagieren zu können, müssen wir 
        # entsprechende Handler registrieren.
        self.client.RegisterHandler('message', self.msg_rcv)
        self.client.RegisterHandler('presence', self.pres_rcv)

        # Die Authentifizierung am Server:
        self.client.auth(jid.getNode(), pwd, resource=jid.getResource())

        # Und schlussendlich das Betreten des Raums:
        p = xmpp.Presence(to='%s/%s' % (room, botname))
        p.setTag('x', namespace=xmpp.NS_MUC).setTagData('password', roompwd)
        p.getTag('x').addChild('history', {'maxchars':'0', 'maxstanzas':'0'})
        self.client.send(p)

# Möchte der Bot etwas sagen, wird vom xmpp-Modul die xmpp Stanza zusammengebaut
# und an den Chatraum gesendet. 
    def say(self, msg):
        m = xmpp.Message(to=self.room, body=msg, typ='groupchat')
        self.client.send(m)

# Wenn der Bot eine Nachricht empfängt, wird folgende Methode aufgerufen:
    def msg_rcv(self, sess, msg):

        # Wir ignorieren Nachrichten, die wir selbst verschickt haben.
        sender = str(msg.getFrom())
        if len(sender.split('/')) > 1:
            sender = sender.split('/')[1]
        if sender.lower().find(self.botname) >= 0:
            return

        self.react(msg.getBody())

# In der folgenden Methode wird für jedes Keyword, dass wir gespeichert haben 
# geschaut, ob dieses in der empfangenen Nachricht gefunden werden kann. Falls 
# ja, antwortet der Bot mit einer zufällig ausgewählten Antwort aus der Menge
# aller passenden Antworten.
    def react(self, msg):
        time.sleep(self.delay)
        for pattern in self.reactions.keys():
            print "trying to find %s in %s" % (pattern, msg)
            if pattern.search(msg):
                self.say(self.reactions[pattern]
                        [randint(0,len(self.reactions[pattern])-1)])
                return

# Die folgende Endlosschleife wird aufgerufen, wenn der Bot im Chat bleiben und
# auf ankommende Nachrichten warten soll.
    def processing(self):
        while True:
            self.client.Process(1)

# Wenn der Bot gestartet wird, beginnt er mit dem Warten auf Nachrichten. Falls
# er bei der Initialisierung eine Liste von Zitaten übergeben bekommen hat,
# zitiert er aus dieser Liste in zufälligen Abständen zufällige Zitate.
    def run(self):
        processor = Thread()
        processor.run = self.processing
        processor.start()
        if self.minwait==-1 or self.maxwait==-1:
            return
        while True:
            r = randint(self.minwait, self.maxwait)
            time.sleep(r)
            self.say(self.quotes[randint(0,len(self.quotes)-1)])

Das mucbot-Projekt ist frei auf github verfügbar. Es steht unter einer GNU General Public License. Eigentlich bin ich eher ein Fan von BSD und ähnlichen Lizenzen, aber die Verwendung von xmpppy macht dies notwendig.

Vielleicht kann ja der eine oder andere Teile des Mucbots verwenden oder findet hier Anregungen für neue Projekte. Ich grüße mit diesem meinem ersten Blogeintrag alle Leser von IOException.de und freue mich schon darauf bald weitere spannende Dinge mit der Welt zu teilen.

ioexception.de

Benjamin Erb [] studiert seit 2006 Medieninformatik und interessiert sich insbesondere für Java, Web-Technologien, Ubiquitous Computing, Cloud Computing, verteilte Systeme und Informationsdesign.


Raimar Wagner studiert seit 2005 Informatik mit Anwendungsfach Medizin und interessiert sich für C++ stl, boost & Qt Programmierung, Scientific Visualization, Computer Vision und parallele Rechenkonzepte.


David Langer studiert seit 2006 Medieninformatik und interessiert sich für Web-Entwicklung, jQuery, Business Process Management und Java.


Sebastian Schimmel studiert seit 2006 Informatik mit Anwendungsfach Medizin und interessiert sich für hardwarenahe Aspekte, Robotik, webOs, C/C++ und UNIX/Linux.


Timo Müller studiert seit 2006 Medieninformatik. Er interessiert sich allen voran für Mobile and Ubiquitous Computing, systemnahe Enwticklung und verteilte Systeme, sowie Computer Vision.


Achim Strauß studiert seit 2006 Medieninformatik. Seine Interessen liegen in Themen der Mensch-Computer Interaktion sowie Webentwicklung und UNIX/Linux.


Tobias Schlecht studiert seit 2006 Medieninformatik und interessiert sich vor allem für Software Engineering, Model Driven Architecture, Requirements Engineering, Usability Engineering, Web-Technologien, UML2 und Java.


Fabian Groh studiert seit 2006 Medieninformatik. Seine Interessengebiete sind Computer Graphics, Computer Vision, Computational Photography sowie Ubiquitos Computing.


Matthias Matousek studiert seit 2007 Medieninformatik und interessiert sich besonders für Skriptsprachen, Echtzeitsysteme und Kommunikation.


Michael Müller [] studiert seit 2009 Medieninformatik. Er interessiert sich vor allem für Web-Technologien, Ubiquitous Computing, User-Interfaces, UNIX und Creative Coding.


Falco Nogatz [] studiert seit 2010 Informatik mit Anwendungsfach Mathematik. Er interessiert sich für Web-Technologien, Programmierparadigmen und theoretische Grundlagen.

Archiv

Februar 2015
M D M D F S S
« Mrz    
 1
2345678
9101112131415
16171819202122
232425262728