FLOW
__copyright__ = 'this file is in the public domain'
- receive string from server
- make string into an ircevent
- basic handling of the ircevent
- check if the event is a command to the bot, if so execute it
- check to see if it triggers any callbacks
receive string and make it an ircevent
in gozerbot/irc.py:
# read on socket .. make ircevent .. call the handle_ievent method res = self.fsock.readline() ievent = Ircevent().parse(self, res) self.handle_ievent(ievent)
basic handling of the ircevent
in gozerbot/bot.py:
def handle_ievent(self, ievent):
""" call Irc class method .. add to backlog .. check for callbacks """
j = Ircevent()
Irc.handle_ievent(self, ievent)
self.backlog.append(ievent)
j.copyin(ievent)
callbacks.check(self, j)
in gozerbot/irc.py:
def handle_ievent(self, ievent):
""" handle ircevent .. dispatch to method """
try:
# see if the irc object has a method to handle the ievent
method = getattr(self,'handle_' + ievent.cmnd.lower())
# try to call method
try:
method(ievent)
except:
handle_exception()
except AttributeError:
pass
# see if there are wait callbacks
self.wait.check(ievent)
this will call a function handle_CMND on the bot.
command handling
in gozerbot/bot.py:
the handle_privmsg function handles the PRIVMSG commands and checks if a command is given and if so calls plugins.trydispatch()
in gozerbot/plugins.py:
the trydispatch function checks if the user should be ignored, if not checks for pipelining or multiple commands. in case of pipelining the ircevent queues entry will be chained. each command runs a dispatch function in its own thread. variables: what is one of redispatcher of commands object, com is the command triggered, bot is the bot on which the command is given and ievent is the ircevent that triggered the command
def dispatch(self, what, com, bot, ievent): """ dispatch ievent """ if bot.stopped: return 0 # check for user provided channel if com.options: makeoptions(ievent, com.options) else: makeoptions(ievent) makeargrest(ievent) ievent.usercmnd = 1 rlog(10, 'plugins', 'dispatching %s for %s' % (ievent.command, ievent.userhost)) what.dispatch(com, bot, ievent) return 1dispatch pushes the triggered command to the dispatch function of what, which can be a REdispatcher or Commands object.
in gozerbot/redispatcher.py or gozerbot/commands.py:
this is were the actual dispatch is taking place, the command or re callback gets two arguments passed .. the bot and the ircevent. dispatching is done in a thread or in one of the command runners. command runners are worker threads the cant execute commands sequentialy.
def dispatch(self, com, bot, ievent): """ dispatch on ircevent passing bot an ievent as arguments """ if bot.stopped: return 0 stats.up('cmnds', com.name) stats.up('cmnds', com.plugname) stats.up('cmnds', 'speed%s' % com.speed) # execute command if com.threaded: start_bot_command(com.func, (bot, ievent)) else: speed = ievent.speed or com.speed ievent.speed = speed cmndrunners[10-speed].put(com.name, com.func, bot, ievent) return 1
callback handling
in gozerbot/callbacks.py:
this functions checks to see if any callback for an ircevent is registered and if so calls self.callback that will do the actual firing of the callback.
def check(self, bot, ievent): """ check for callbacks to be fired """ # check for "ALL" callbacks if self.cbs.has_key('ALL'): for cb in self.cbs['ALL']: self.callback(cb, bot, ievent) cmnd = ievent.cmnd.upper() # check for CMND callbacks if self.cbs.has_key(cmnd): for cb in self.cbs[cmnd]: self.callback(cb, bot, ievent)snippet of self.callback:
every callback has a optional test function that is used to determine if the callback should fire or not .. cb.prereq. the actual callback is called in its own thread or in the main bot loop
# see if the callback pre requirement succeeds if cb.prereq: rlog(-10, 'callback', 'excecuting in loop %s' % str(cb.prereq)) if not cb.prereq(bot, ievent): return # check if callback function is there if not cb.func: return # start callback in its own thread rlog(-10, 'callback', 'excecuting callback %s' % str(cb.func)) if cb.threaded: thr.start_new_thread(cb.func, (bot, ievent), cb.kwargs) else: cb.func(bot, ievent, **cb.kwargs)