Prepare hooks to be used for other things than Message
This commit is contained in:
parent
877041bb12
commit
8c52f75b6a
15
bot.py
15
bot.py
@ -31,8 +31,8 @@ __author__ = 'nemunaire'
|
||||
|
||||
from consumer import Consumer, EventConsumer, MessageConsumer
|
||||
from event import ModuleEvent
|
||||
import hooks
|
||||
from hooksmanager import HooksManager
|
||||
from hooks.messagehook import MessageHook
|
||||
from hooks.manager import HooksManager
|
||||
from networkbot import NetworkBot
|
||||
from server.IRC import IRCServer
|
||||
from server.DCC import DCC
|
||||
@ -82,7 +82,7 @@ class Bot(threading.Thread):
|
||||
def in_ping(msg):
|
||||
if re.match("^ *(m[' ]?entends?[ -]+tu|h?ear me|do you copy|ping)", msg.text, re.I) is not None:
|
||||
return response.Response(msg.sender, message="pong", channel=msg.receivers, nick=msg.nick)
|
||||
self.hooks.add_hook(hooks.Hook(in_ping), "in", "PRIVMSG")
|
||||
self.hooks.add_hook(MessageHook(in_ping), "in", "PRIVMSG")
|
||||
|
||||
def _help_msg(msg):
|
||||
"""Parse and response to help messages"""
|
||||
@ -119,7 +119,7 @@ class Bot(threading.Thread):
|
||||
" de tous les modules disponibles localement",
|
||||
message=["\x03\x02%s\x03\x02 (%s)" % (im, self.modules[im].__doc__) for im in self.modules if self.modules[im].__doc__])
|
||||
return res
|
||||
self.hooks.add_hook(hooks.Hook(_help_msg, "help"), "in", "PRIVMSG", "cmd")
|
||||
self.hooks.add_hook(MessageHook(_help_msg, "help"), "in", "PRIVMSG", "cmd")
|
||||
|
||||
# Other known bots, making a bots network
|
||||
self.network = dict()
|
||||
@ -479,9 +479,10 @@ def reload():
|
||||
|
||||
import hooks
|
||||
imp.reload(hooks)
|
||||
|
||||
import hooksmanager
|
||||
imp.reload(hooksmanager)
|
||||
import hooks.manager
|
||||
imp.reload(hooks.manager)
|
||||
import hooks.messagehook
|
||||
imp.reload(hooks.messagehook)
|
||||
|
||||
import importer
|
||||
imp.reload(importer)
|
||||
|
106
hooks.py
106
hooks.py
@ -1,106 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Nemubot is a modulable IRC bot, built around XML configuration files.
|
||||
# Copyright (C) 2012 Mercier Pierre-Olivier
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from response import Response
|
||||
from exception import IRCException
|
||||
|
||||
logger = logging.getLogger("nemubot.hooks")
|
||||
|
||||
class Hook:
|
||||
"""Class storing hook informations"""
|
||||
def __init__(self, call, name=None, data=None, regexp=None, channels=list(), server=None, end=None, call_end=None, help=None):
|
||||
self.name = name
|
||||
self.end = end
|
||||
self.call = call
|
||||
if call_end is None:
|
||||
self.call_end = self.call
|
||||
else:
|
||||
self.call_end = call_end
|
||||
self.regexp = regexp
|
||||
self.data = data
|
||||
self.times = -1
|
||||
self.server = server
|
||||
self.channels = channels
|
||||
self.help = help
|
||||
|
||||
def match(self, message, channel=None, server=None):
|
||||
if isinstance(message, Response):
|
||||
return self.is_matching(None, channel, server)
|
||||
elif message.qual == "cmd":
|
||||
return self.is_matching(message.cmds[0], channel, server)
|
||||
elif hasattr(message, "text"):
|
||||
return self.is_matching(message.text, channel, server)
|
||||
elif len(message.params) > 0:
|
||||
return self.is_matching(message.params[0], channel, server)
|
||||
else:
|
||||
return self.is_matching(message.cmd, channel, server)
|
||||
|
||||
def is_matching(self, strcmp, channel=None, server=None):
|
||||
"""Test if the current hook correspond to the message"""
|
||||
return (channel is None or len(self.channels) <= 0 or
|
||||
channel in self.channels) and (server is None or
|
||||
self.server is None or self.server == server) and (
|
||||
(self.name is None or strcmp == self.name) and (
|
||||
self.end is None or strcmp == self.end) and (
|
||||
self.regexp is None or re.match(self.regexp, strcmp)))
|
||||
|
||||
def run(self, msg, data2=None, strcmp=None):
|
||||
"""Run the hook"""
|
||||
if self.times != 0:
|
||||
self.times -= 1
|
||||
|
||||
if (self.end is not None and strcmp is not None and
|
||||
self.call_end is not None and strcmp == self.end):
|
||||
call = self.call_end
|
||||
self.times = 0
|
||||
else:
|
||||
call = self.call
|
||||
|
||||
try:
|
||||
if self.data is None:
|
||||
if data2 is None:
|
||||
return call(msg)
|
||||
elif isinstance(data2, dict):
|
||||
return call(msg, **data2)
|
||||
else:
|
||||
return call(msg, data2)
|
||||
elif isinstance(self.data, dict):
|
||||
if data2 is None:
|
||||
return call(msg, **self.data)
|
||||
else:
|
||||
return call(msg, data2, **self.data)
|
||||
else:
|
||||
if data2 is None:
|
||||
return call(msg, self.data)
|
||||
elif isinstance(data2, dict):
|
||||
return call(msg, self.data, **data2)
|
||||
else:
|
||||
return call(msg, self.data, data2)
|
||||
except IRCException as e:
|
||||
return e.fill_response(msg)
|
||||
|
||||
last_registered = []
|
||||
|
||||
def hook(store, *args, **kargs):
|
||||
def sec(call):
|
||||
last_registered.append((store, Hook(call, *args, **kargs)))
|
||||
return call
|
||||
return sec
|
76
hooks/__init__.py
Normal file
76
hooks/__init__.py
Normal file
@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Nemubot is a smart and modulable IM bot.
|
||||
# Copyright (C) 2012-2014 nemunaire
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from exception import IRCException
|
||||
|
||||
def call_game(call, *args, **kargs):
|
||||
"""TODO"""
|
||||
l = list()
|
||||
d = kargs
|
||||
|
||||
for a in args:
|
||||
if a is not None:
|
||||
if isinstance(a, dict):
|
||||
d.update(a)
|
||||
else:
|
||||
l.append(a)
|
||||
|
||||
return call(*l, **d)
|
||||
|
||||
|
||||
class AbstractHook:
|
||||
|
||||
"""Abstract class for Hook implementation"""
|
||||
|
||||
def __init__(self, call, data=None, mtimes=-1, end_call=None):
|
||||
self.call = call
|
||||
self.data = data
|
||||
|
||||
self.times = mtimes
|
||||
self.end_call = end_call
|
||||
|
||||
|
||||
def match(self, data1, server):
|
||||
return NotImplemented
|
||||
|
||||
|
||||
def run(self, data1, *args):
|
||||
"""Run the hook"""
|
||||
self.times -= 1
|
||||
|
||||
try:
|
||||
ret = call_game(self.call, data1, self.data, *args)
|
||||
except IRCException as e:
|
||||
ret = e.fill_response(data1)
|
||||
finally:
|
||||
if self.times == 0:
|
||||
self.call_end(ret)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
from hooks.messagehook import MessageHook
|
||||
|
||||
last_registered = []
|
||||
|
||||
def hook(store, *args, **kargs):
|
||||
"""Function used as a decorator for module loading"""
|
||||
def sec(call):
|
||||
last_registered.append((store, MessageHook(call, *args, **kargs)))
|
||||
return call
|
||||
return sec
|
61
hooks/messagehook.py
Normal file
61
hooks/messagehook.py
Normal file
@ -0,0 +1,61 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Nemubot is a smart and modulable IM bot.
|
||||
# Copyright (C) 2012-2014 nemunaire
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import re
|
||||
|
||||
from exception import IRCException
|
||||
import hooks
|
||||
from response import Response
|
||||
|
||||
class MessageHook(hooks.AbstractHook):
|
||||
|
||||
"""Class storing hook information, specialized for a generic Message"""
|
||||
|
||||
def __init__(self, call, name=None, data=None, regexp=None,
|
||||
channels=list(), server=None, mtimes=-1, end_call=None):
|
||||
|
||||
hooks.AbstractHook.__init__(self, call=call, data=data,
|
||||
end_call=end_call, mtimes=mtimes)
|
||||
|
||||
self.name = name
|
||||
self.regexp = regexp
|
||||
self.server = server
|
||||
self.channels = channels
|
||||
|
||||
|
||||
def match(self, message, server=None):
|
||||
if isinstance(message, Response):
|
||||
return self.is_matching(None, message.channel, server)
|
||||
|
||||
elif message.qual == "cmd":
|
||||
return self.is_matching(message.cmds[0], message.channel, server)
|
||||
elif hasattr(message, "text"):
|
||||
return self.is_matching(message.text, message.channel, server)
|
||||
elif len(message.params) > 0:
|
||||
return self.is_matching(message.params[0], message.channel, server)
|
||||
else:
|
||||
return self.is_matching(message.cmd, message.channel, server)
|
||||
|
||||
|
||||
def is_matching(self, strcmp, channel=None, server=None):
|
||||
"""Test if the current hook correspond to the message"""
|
||||
return (channel is None or len(self.channels) <= 0 or
|
||||
channel in self.channels) and (server is None or
|
||||
self.server is None or self.server == server) and (
|
||||
(self.name is None or strcmp == self.name) and (
|
||||
self.regexp is None or re.match(self.regexp, strcmp)))
|
@ -34,7 +34,7 @@ def help_full():
|
||||
return "!conjugaison <tens> <verb>: give the conjugaison for <verb> in <tens>."
|
||||
|
||||
|
||||
@hook("cmd_hook", "conjugaison", help="!conjugaison <tens> <verb>: give the conjugaison for <verb> in <tens>.")
|
||||
@hook("cmd_hook", "conjugaison")
|
||||
def cmd_conjug(msg):
|
||||
if len(msg.cmds) < 3:
|
||||
raise IRCException("donne moi un temps et un verbe, et je te donnerai sa conjugaison!")
|
||||
|
@ -14,7 +14,7 @@ import traceback
|
||||
nemubotversion = 3.4
|
||||
|
||||
from event import ModuleEvent
|
||||
from hooks import Hook, hook
|
||||
from hooks import hook
|
||||
from tools.date import extractDate
|
||||
from tools.countdown import countdown_format, countdown
|
||||
|
||||
@ -60,8 +60,9 @@ def cmd_we(msg):
|
||||
"Youhou, on est en week-end depuis %s."),
|
||||
channel=msg.channel)
|
||||
|
||||
@hook("cmd_hook", "start", help="!start /something/: launch a timer")
|
||||
@hook("cmd_hook", "start")
|
||||
def start_countdown(msg):
|
||||
"""!start /something/: launch a timer"""
|
||||
if len(msg.cmds) < 2:
|
||||
raise IRCException("indique le nom d'un événement à chronométrer")
|
||||
if msg.cmds[1] in DATAS.index:
|
||||
@ -154,8 +155,9 @@ def end_countdown(msg):
|
||||
else:
|
||||
return Response(msg.sender, "%s n'est pas un compteur connu."% (msg.cmds[1]), channel=msg.channel, nick=msg.nick)
|
||||
|
||||
@hook("cmd_hook", "eventslist", help="!eventslist: gets list of timer")
|
||||
@hook("cmd_hook", "eventslist")
|
||||
def liste(msg):
|
||||
"""!eventslist: gets list of timer"""
|
||||
if len(msg.cmds) > 1:
|
||||
res = list()
|
||||
for user in msg.cmds[1:]:
|
||||
|
@ -15,8 +15,8 @@ def load(context):
|
||||
"http://developer.mapquest.com/")
|
||||
return None
|
||||
|
||||
from hooks import Hook
|
||||
add_hook("cmd_hook", Hook(cmd_geocode, "geocode"))
|
||||
from hooks.messagehook import MessageHook
|
||||
add_hook("cmd_hook", MessageHook(cmd_geocode, "geocode"))
|
||||
|
||||
|
||||
def help_tiny ():
|
||||
|
@ -9,7 +9,7 @@ import socket
|
||||
import subprocess
|
||||
import urllib
|
||||
|
||||
from hooks import Hook, hook
|
||||
from hooks import hook
|
||||
from tools import web
|
||||
|
||||
nemubotversion = 3.4
|
||||
@ -21,7 +21,8 @@ def load(context):
|
||||
"<whoisxmlapi username=\"XX\" password=\"XXX\" />\nRegister at "
|
||||
"http://www.whoisxmlapi.com/newaccount.php")
|
||||
else:
|
||||
add_hook("cmd_hook", Hook(cmd_whois, "netwhois"))
|
||||
from hooks.messagehook import MessageHook
|
||||
add_hook("cmd_hook", MessageHook(cmd_whois, "netwhois"))
|
||||
|
||||
def help_full():
|
||||
return "!traceurl /url/: Follow redirections from /url/."
|
||||
|
@ -15,7 +15,7 @@ def help_full():
|
||||
|
||||
LAST_SUBS = dict()
|
||||
|
||||
@hook("cmd_hook", "subreddit", help="!subreddit /subreddit/: Display information on the subreddit.")
|
||||
@hook("cmd_hook", "subreddit")
|
||||
def cmd_subreddit(msg):
|
||||
global LAST_SUBS
|
||||
if len(msg.cmds) <= 1:
|
||||
|
@ -12,9 +12,9 @@ from hooks import hook
|
||||
nemubotversion = 3.4
|
||||
|
||||
def help_full():
|
||||
return "If you would like to sleep soon, use !sleepytime to know the best time to wake up; use !sleepytime hh:mm if you want to wake up at hh:mm"
|
||||
return "If you would like to sleep soon, use !sleepytime to know the best time to wake up; use !sleepytime hh:mm if you want to wake up at hh:mm"
|
||||
|
||||
@hook("cmd_hook", "sleepytime", help="If you would like to sleep soon, use !sleepytime to know the best time to wake up; use !sleepytime hh:mm if you want to wake up at hh:mm")
|
||||
@hook("cmd_hook", "sleepytime")
|
||||
def cmd_sleep(msg):
|
||||
if len (msg.cmds) > 1 and re.match("[0-9]{1,2}[h':.,-]([0-9]{1,2})?[m'\":.,-]?",
|
||||
msg.cmds[1]) is not None:
|
||||
|
@ -15,7 +15,7 @@ nemubotversion = 3.4
|
||||
def help_full():
|
||||
return "!syno <word>: give a list of synonyms for <word>."
|
||||
|
||||
@hook("cmd_hook", "synonymes", help="!syno <word>: give a list of synonyms for <word>.")
|
||||
@hook("cmd_hook", "synonymes")
|
||||
def cmd_syno(msg):
|
||||
return go("synonymes", msg)
|
||||
|
||||
|
@ -28,8 +28,8 @@ def load(context):
|
||||
else:
|
||||
URL = URL % CONF.getNode("wrapi")["key"]
|
||||
|
||||
from hooks import Hook
|
||||
add_hook("cmd_hook", Hook(cmd_translate, "translate"))
|
||||
from hooks.messagehook import MessageHook
|
||||
add_hook("cmd_hook", MessageHook(cmd_translate, "translate"))
|
||||
|
||||
|
||||
def help_full():
|
||||
|
@ -25,10 +25,10 @@ def load(context):
|
||||
"http://developer.forecast.io/")
|
||||
return None
|
||||
|
||||
from hooks import Hook
|
||||
add_hook("cmd_hook", Hook(cmd_weather, "météo"))
|
||||
add_hook("cmd_hook", Hook(cmd_alert, "alert"))
|
||||
add_hook("cmd_hook", Hook(cmd_coordinates, "coordinates"))
|
||||
from hooks.messagehook import MessageHook
|
||||
add_hook("cmd_hook", MessageHook(cmd_weather, "météo"))
|
||||
add_hook("cmd_hook", MessageHook(cmd_alert, "alert"))
|
||||
add_hook("cmd_hook", MessageHook(cmd_coordinates, "coordinates"))
|
||||
|
||||
|
||||
def help_full ():
|
||||
|
@ -10,13 +10,11 @@ from urllib.request import urlopen
|
||||
|
||||
nemubotversion = 3.4
|
||||
|
||||
from hooks import hook
|
||||
|
||||
API_URL="http://worldcup.sfg.io/%s"
|
||||
|
||||
def load(context):
|
||||
from hooks import Hook
|
||||
add_hook("cmd_hook", Hook(cmd_watch, "watch_worldcup"))
|
||||
add_hook("cmd_hook", Hook(cmd_worldcup, "worldcup"))
|
||||
|
||||
from event import ModuleEvent
|
||||
add_event(ModuleEvent(func=lambda url: urlopen(url, timeout=10).read().decode(), func_data=API_URL % "matches/current?by_date=DESC", call=current_match_new_action, intervalle=30))
|
||||
|
||||
@ -37,6 +35,7 @@ def start_watch(msg):
|
||||
save()
|
||||
raise IRCException("This channel is now watching world cup events!")
|
||||
|
||||
@hook("cmd_hook", "watch_worldcup")
|
||||
def cmd_watch(msg):
|
||||
global DATAS
|
||||
|
||||
@ -178,6 +177,7 @@ def get_matches(url):
|
||||
if is_valid(match):
|
||||
yield match
|
||||
|
||||
@hook("cmd_hook", "worldcup")
|
||||
def cmd_worldcup(msg):
|
||||
res = Response(msg.sender, channel=msg.channel, nomore="No more match to display", count=" (%d more matches)")
|
||||
nb = len(msg.cmds)
|
||||
|
@ -24,7 +24,7 @@ def gen_response(res, msg, srv):
|
||||
else:
|
||||
raise IRCException("mauvaise URL : %s" % srv)
|
||||
|
||||
@hook("cmd_hook", "ycc", help="!ycc [<url>]: with an argument, reduce the given <url> thanks to ycc.fr; without argument, reduce the last URL said on the current channel.")
|
||||
@hook("cmd_hook", "ycc")
|
||||
def cmd_ycc(msg):
|
||||
if len(msg.cmds) == 1:
|
||||
global LAST_URLS
|
||||
|
Loading…
Reference in New Issue
Block a user