diff --git a/bot.py b/bot.py
index 3f704f3..786be74 100644
--- a/bot.py
+++ b/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)
diff --git a/hooks.py b/hooks.py
deleted file mode 100644
index 4d52135..0000000
--- a/hooks.py
+++ /dev/null
@@ -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 .
-
-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
diff --git a/hooks/__init__.py b/hooks/__init__.py
new file mode 100644
index 0000000..e1fa0cf
--- /dev/null
+++ b/hooks/__init__.py
@@ -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 .
+
+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
diff --git a/hooksmanager.py b/hooks/manager.py
similarity index 100%
rename from hooksmanager.py
rename to hooks/manager.py
diff --git a/hooks/messagehook.py b/hooks/messagehook.py
new file mode 100644
index 0000000..2ae3572
--- /dev/null
+++ b/hooks/messagehook.py
@@ -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 .
+
+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)))
diff --git a/modules/conjugaison.py b/modules/conjugaison.py
index 9d9c492..d5ae720 100644
--- a/modules/conjugaison.py
+++ b/modules/conjugaison.py
@@ -34,7 +34,7 @@ def help_full():
return "!conjugaison : give the conjugaison for in ."
-@hook("cmd_hook", "conjugaison", help="!conjugaison : give the conjugaison for in .")
+@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!")
diff --git a/modules/events.py b/modules/events.py
index f7901c6..90191b1 100644
--- a/modules/events.py
+++ b/modules/events.py
@@ -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:]:
diff --git a/modules/mapquest.py b/modules/mapquest.py
index 17e7eb8..e2487a6 100644
--- a/modules/mapquest.py
+++ b/modules/mapquest.py
@@ -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 ():
diff --git a/modules/networking.py b/modules/networking.py
index e573a34..b83e8f7 100644
--- a/modules/networking.py
+++ b/modules/networking.py
@@ -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):
"\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/."
diff --git a/modules/reddit.py b/modules/reddit.py
index b7ff786..39eb049 100644
--- a/modules/reddit.py
+++ b/modules/reddit.py
@@ -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:
diff --git a/modules/sleepytime.py b/modules/sleepytime.py
index cf45af6..b539a9e 100644
--- a/modules/sleepytime.py
+++ b/modules/sleepytime.py
@@ -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:
diff --git a/modules/syno.py b/modules/syno.py
index 548d89f..81e392b 100644
--- a/modules/syno.py
+++ b/modules/syno.py
@@ -15,7 +15,7 @@ nemubotversion = 3.4
def help_full():
return "!syno : give a list of synonyms for ."
-@hook("cmd_hook", "synonymes", help="!syno : give a list of synonyms for .")
+@hook("cmd_hook", "synonymes")
def cmd_syno(msg):
return go("synonymes", msg)
diff --git a/modules/translate.py b/modules/translate.py
index 8191d3b..6a19640 100644
--- a/modules/translate.py
+++ b/modules/translate.py
@@ -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():
diff --git a/modules/weather.py b/modules/weather.py
index dfcb583..3f865c8 100644
--- a/modules/weather.py
+++ b/modules/weather.py
@@ -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 ():
diff --git a/modules/worldcup.py b/modules/worldcup.py
index c32b133..04db62a 100644
--- a/modules/worldcup.py
+++ b/modules/worldcup.py
@@ -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)
diff --git a/modules/ycc.py b/modules/ycc.py
index c450d0d..8c9a3b0 100644
--- a/modules/ycc.py
+++ b/modules/ycc.py
@@ -24,7 +24,7 @@ def gen_response(res, msg, srv):
else:
raise IRCException("mauvaise URL : %s" % srv)
-@hook("cmd_hook", "ycc", help="!ycc []: with an argument, reduce the given 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