ircbot: attempt to bring recursion back
so initial tests suggest this is working well, but it's not exactly the clearest code, so let's call this a rough proof of concept of recursion in the bot
This commit is contained in:
parent
115e82f0fc
commit
5716e285b6
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import bisect
|
import bisect
|
||||||
import collections
|
import collections
|
||||||
|
import copy
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import ssl
|
import ssl
|
||||||
@ -98,6 +99,8 @@ class DrReactor(irc.client.Reactor):
|
|||||||
log.debug("EVENT: e[%s] s[%s] t[%s] a[%s]", event.type, event.source,
|
log.debug("EVENT: e[%s] s[%s] t[%s] a[%s]", event.type, event.source,
|
||||||
event.target, event.arguments)
|
event.target, event.arguments)
|
||||||
|
|
||||||
|
self.try_recursion(connection, event)
|
||||||
|
|
||||||
# only do aliasing for pubmsg/privmsg
|
# only do aliasing for pubmsg/privmsg
|
||||||
if event.type in ['pubmsg', 'privmsg']:
|
if event.type in ['pubmsg', 'privmsg']:
|
||||||
what = event.arguments[0]
|
what = event.arguments[0]
|
||||||
@ -132,10 +135,138 @@ class DrReactor(irc.client.Reactor):
|
|||||||
self.handlers.get(event.type, [])
|
self.handlers.get(event.type, [])
|
||||||
)
|
)
|
||||||
for handler in matching_handlers:
|
for handler in matching_handlers:
|
||||||
|
log.debug(u"not-match")
|
||||||
result = handler.callback(connection, event)
|
result = handler.callback(connection, event)
|
||||||
if result == "NO MORE":
|
if result == "NO MORE":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def try_recursion(self, connection, event):
|
||||||
|
"""Scan message for subcommands to execute and use as part of this command.
|
||||||
|
|
||||||
|
Upon seeing a line intended for this module, see if there are subcommands
|
||||||
|
that we should do what is basically a text replacement on. The intent is to
|
||||||
|
allow things like the following:
|
||||||
|
|
||||||
|
command arg1 [anothercommand arg1 arg2]
|
||||||
|
|
||||||
|
where the output of anothercommand is command's arg2..n.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
connection source connection
|
||||||
|
event incoming event
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
log.debug(u"RECURSING EVENT: e[%s] s[%s] t[%s] a[%s]", event.type, event.source,
|
||||||
|
event.target, event.arguments)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# begin recursion search
|
||||||
|
attempt = event.arguments[0]
|
||||||
|
|
||||||
|
log.debug(u"checking it against %s", attempt)
|
||||||
|
|
||||||
|
start_idx = attempt.find('[')
|
||||||
|
subcmd = attempt[start_idx+1:]
|
||||||
|
end_idx = subcmd.rfind(']')
|
||||||
|
subcmd = subcmd[:end_idx]
|
||||||
|
|
||||||
|
if start_idx != -1 and end_idx != -1 and len(subcmd) > 0:
|
||||||
|
log.debug(u"subcmd: %s", subcmd)
|
||||||
|
|
||||||
|
# found recursion candidate
|
||||||
|
# copy the event and see if IT has recursion to do
|
||||||
|
newevent = copy.deepcopy(event)
|
||||||
|
newevent.arguments[0] = subcmd
|
||||||
|
newevent._recursing = True
|
||||||
|
|
||||||
|
log.debug(u"new event copied")
|
||||||
|
|
||||||
|
self.try_recursion(connection, newevent)
|
||||||
|
|
||||||
|
# now that we have a string that has been
|
||||||
|
# recursed all the way deeper into its text, see if any
|
||||||
|
# modules can do something with it. this calls the same
|
||||||
|
# event handlers in the same way as if this were a native
|
||||||
|
# event.
|
||||||
|
self.try_to_replace_event_text_with_module_text(connection, newevent)
|
||||||
|
|
||||||
|
# we have done all we can do with the sub-event. whatever
|
||||||
|
# the text of that event now is, we should replace the parent
|
||||||
|
# event's [] section with it.
|
||||||
|
oldtext = event.arguments[0]
|
||||||
|
newtext = oldtext.replace('['+subcmd+']', newevent.arguments[0])
|
||||||
|
log.debug(u"oldtext: '%s' newtext: '%s'", oldtext, newtext)
|
||||||
|
event.arguments[0] = newtext
|
||||||
|
|
||||||
|
# we have now resolved the []. recursion will unfold, replacing
|
||||||
|
# it further and further, until we eventually get back to the
|
||||||
|
# original irc event in _handle_event, which will do one
|
||||||
|
# last search on the text.
|
||||||
|
else:
|
||||||
|
log.debug(u"no more recursion here")
|
||||||
|
except IndexError:
|
||||||
|
log.debug(u"no more recursion here")
|
||||||
|
|
||||||
|
def try_to_replace_event_text_with_module_text(self, connection, event):
|
||||||
|
"""Do something very similar to _handle_event, but for recursion.
|
||||||
|
|
||||||
|
The intent here is that we replace [text] with whatever a module
|
||||||
|
provides to us.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
connection source connection
|
||||||
|
event incoming event
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
replies = []
|
||||||
|
|
||||||
|
# only do aliasing for pubmsg/privmsg
|
||||||
|
if event.type in ['pubmsg', 'privmsg']:
|
||||||
|
what = event.arguments[0]
|
||||||
|
log.debug(u"checking for (recursion) alias for %s", what)
|
||||||
|
|
||||||
|
for alias in Alias.objects.all():
|
||||||
|
repl = alias.replace(what)
|
||||||
|
if repl:
|
||||||
|
# we found an alias for our given string, doing a replace
|
||||||
|
event.arguments[0] = repl
|
||||||
|
|
||||||
|
with self.mutex:
|
||||||
|
# doing regex version first as it has the potential to be more specific
|
||||||
|
log.debug(u"checking (recursion) regex handlers for %s", event.type)
|
||||||
|
matching_handlers = sorted(
|
||||||
|
self.regex_handlers.get("all_events", []) +
|
||||||
|
self.regex_handlers.get(event.type, [])
|
||||||
|
)
|
||||||
|
log.debug(u"got %d", len(matching_handlers))
|
||||||
|
for handler in matching_handlers:
|
||||||
|
log.debug(u"checking (recursion) %s vs. %s", handler, event.arguments)
|
||||||
|
for line in event.arguments:
|
||||||
|
match = re.search(handler.regex, line)
|
||||||
|
if match:
|
||||||
|
log.debug(u"match (recursion)!")
|
||||||
|
result = handler.callback(connection, event, match)
|
||||||
|
log.debug(u"result: %s", result)
|
||||||
|
if result:
|
||||||
|
log.debug(u"appending %s to replies", result)
|
||||||
|
replies.append(result)
|
||||||
|
|
||||||
|
matching_handlers = sorted(
|
||||||
|
self.handlers.get("all_events", []) +
|
||||||
|
self.handlers.get(event.type, [])
|
||||||
|
)
|
||||||
|
for handler in matching_handlers:
|
||||||
|
log.debug(u"not-match (recursion)")
|
||||||
|
result = handler.callback(connection, event)
|
||||||
|
log.debug(u"result: %s", result)
|
||||||
|
if result:
|
||||||
|
log.debug(u"appending %s to replies", result)
|
||||||
|
replies.append(result)
|
||||||
|
|
||||||
|
if len(replies):
|
||||||
|
event.arguments[0] = '\n'.join(replies)
|
||||||
|
|
||||||
|
|
||||||
class IRCBot(irc.client.SimpleIRCClient):
|
class IRCBot(irc.client.SimpleIRCClient):
|
||||||
@ -514,10 +645,13 @@ class IRCBot(irc.client.SimpleIRCClient):
|
|||||||
"NO MORE" to stop other event handlers from acting.
|
"NO MORE" to stop other event handlers from acting.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
log.debug(u"in reply for e[%s] r[%s]", event, replystr)
|
||||||
replypath = ircbotlib.reply_destination_for_event(event)
|
replypath = ircbotlib.reply_destination_for_event(event)
|
||||||
|
log.debug(u"replypath: %s", replypath)
|
||||||
|
|
||||||
if replystr is not None:
|
if replystr is not None:
|
||||||
recursing = getattr(event, '_recursing', False)
|
recursing = getattr(event, '_recursing', False)
|
||||||
|
log.debug("determined recursing to be %s", recursing)
|
||||||
if recursing:
|
if recursing:
|
||||||
return replystr
|
return replystr
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user