Refactors hooks registration
This commit is contained in:
parent
49d7e4ced6
commit
f39a0eac56
40 changed files with 202 additions and 168 deletions
|
|
@ -79,7 +79,7 @@ class Bot(threading.Thread):
|
|||
def in_echo(msg):
|
||||
from nemubot.message import Text
|
||||
return Text(msg.nick + ": " + " ".join(msg.args), to=msg.to_response)
|
||||
self.treater.hm.add_hook(nemubot.hooks.Message(in_echo, "echo"), "in", "Command")
|
||||
self.treater.hm.add_hook(nemubot.hooks.Command(in_echo, "echo"), "in", "Command")
|
||||
|
||||
def _help_msg(msg):
|
||||
"""Parse and response to help messages"""
|
||||
|
|
@ -98,7 +98,7 @@ class Bot(threading.Thread):
|
|||
elif msg.args[0][0] == "!":
|
||||
for module in self.modules:
|
||||
for (s, h) in self.modules[module].__nemubot_context__.hooks:
|
||||
if s == "in_Command" and (h.name is not None or h.regexp is not None) and h.is_matching(msg.args[0][1:]):
|
||||
if s == "in_Command" and (h.name is not None or h.regexp is not None) and ((h.name is not None and msg.args[0][1:] == h.name) or (h.regexp is not None and re.match(h.regexp, msg.args[0][1:]))):
|
||||
if h.help_usage:
|
||||
lp = ["\x03\x02%s%s\x03\x02: %s" % (msg.args[0], (" " + k if k is not None else ""), h.help_usage[k]) for k in h.help_usage]
|
||||
jp = h.keywords.help()
|
||||
|
|
@ -128,7 +128,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.treater.hm.add_hook(nemubot.hooks.Message(_help_msg, "help"), "in", "Command")
|
||||
self.treater.hm.add_hook(nemubot.hooks.Command(_help_msg, "help"), "in", "Command")
|
||||
|
||||
from queue import Queue
|
||||
# Messages to be treated
|
||||
|
|
@ -462,9 +462,9 @@ class Bot(threading.Thread):
|
|||
|
||||
# Register decorated functions
|
||||
import nemubot.hooks
|
||||
for s, h in nemubot.hooks.last_registered:
|
||||
for s, h in nemubot.hooks.hook.last_registered:
|
||||
module.__nemubot_context__.add_hook(s, h)
|
||||
nemubot.hooks.last_registered = []
|
||||
nemubot.hooks.hook.last_registered = []
|
||||
|
||||
# Launch the module
|
||||
if hasattr(module, "load"):
|
||||
|
|
|
|||
|
|
@ -14,29 +14,54 @@
|
|||
# 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 nemubot.hooks.abstract import Abstract
|
||||
from nemubot.hooks.command import Command
|
||||
from nemubot.hooks.message import Message
|
||||
|
||||
last_registered = []
|
||||
|
||||
class hook:
|
||||
|
||||
last_registered = []
|
||||
|
||||
|
||||
def hook(store, *args, **kargs):
|
||||
"""Function used as a decorator for module loading"""
|
||||
def sec(call):
|
||||
last_registered.append((store, Message(call, *args, **kargs)))
|
||||
return call
|
||||
return sec
|
||||
def _add(store, h, *args, **kwargs):
|
||||
"""Function used as a decorator for module loading"""
|
||||
def sec(call):
|
||||
hook.last_registered.append((store, h(call, *args, **kwargs)))
|
||||
return call
|
||||
return sec
|
||||
|
||||
|
||||
def add(store, *args, **kwargs):
|
||||
return hook._add(store, Abstract, *args, **kwargs)
|
||||
|
||||
def ask(*args, store="in_DirectAsk", **kwargs):
|
||||
return hook._add(store, Message, *args, **kwargs)
|
||||
|
||||
def command(*args, store="in_Command", **kwargs):
|
||||
return hook._add(store, Command, *args, **kwargs)
|
||||
|
||||
def message(*args, store="in_Text", **kwargs):
|
||||
return hook._add(store, Message, *args, **kwargs)
|
||||
|
||||
def post(*args, store="post", **kwargs):
|
||||
return hook._add(store, Abstract, *args, **kwargs)
|
||||
|
||||
def pre(*args, store="pre", **kwargs):
|
||||
return hook._add(store, Abstract, *args, **kwargs)
|
||||
|
||||
|
||||
def reload():
|
||||
global Message
|
||||
import imp
|
||||
|
||||
import nemubot.hooks.abstract
|
||||
imp.reload(nemubot.hooks.abstract)
|
||||
|
||||
import nemubot.hooks.command
|
||||
imp.reload(nemubot.hooks.command)
|
||||
|
||||
import nemubot.hooks.message
|
||||
imp.reload(nemubot.hooks.message)
|
||||
Message = nemubot.hooks.message.Message
|
||||
|
||||
import nemubot.hooks.keywords
|
||||
imp.reload(nemubot.hooks.keywords)
|
||||
|
|
|
|||
|
|
@ -87,6 +87,10 @@ class Abstract:
|
|||
return False
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return ""
|
||||
|
||||
|
||||
def can_write(self, receivers=list(), server=None):
|
||||
return True
|
||||
|
||||
|
|
|
|||
65
nemubot/hooks/command.py
Normal file
65
nemubot/hooks/command.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# Nemubot is a smart and modulable IM bot.
|
||||
# Copyright (C) 2012-2015 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 re
|
||||
|
||||
from nemubot.hooks.message import Message
|
||||
from nemubot.hooks.keywords import NoKeyword
|
||||
from nemubot.hooks.keywords.abstract import Abstract as AbstractKeywords
|
||||
from nemubot.hooks.keywords.dict import Dict as DictKeywords
|
||||
import nemubot.message
|
||||
|
||||
|
||||
class Command(Message):
|
||||
|
||||
"""Class storing hook information, specialized for Command messages"""
|
||||
|
||||
def __init__(self, call, name=None, help_usage=dict(), keywords=NoKeyword(),
|
||||
**kargs):
|
||||
|
||||
super().__init__(call=call, **kargs)
|
||||
|
||||
if isinstance(keywords, dict):
|
||||
keywords = DictKeywords(keywords)
|
||||
|
||||
assert type(help_usage) is dict, help_usage
|
||||
assert isinstance(keywords, AbstractKeywords), keywords
|
||||
|
||||
self.name = str(name) if name is not None else None
|
||||
self.help_usage = help_usage
|
||||
self.keywords = keywords
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "\x03\x02%s\x03\x02%s%s" % (
|
||||
self.name if self.name is not None else "\x03\x1f" + self.regexp + "\x03\x1f" if self.regexp is not None else "",
|
||||
" (restricted to %:%s)" % ((",".join(self.servers) if self.server else "*") + (",".join(self.channels) if self.channels else "*")) if len(self.channels) or len(self.servers) else "",
|
||||
": %s" % self.help if self.help is not None else ""
|
||||
)
|
||||
|
||||
|
||||
def check(self, msg):
|
||||
return self.keywords.check(msg.kwargs) and super().check(msg)
|
||||
|
||||
|
||||
def match(self, msg):
|
||||
if not isinstance(msg, nemubot.message.command.Command):
|
||||
return False
|
||||
else:
|
||||
return (
|
||||
(self.name is None or msg.cmd == self.name) and
|
||||
(self.regexp is None or re.match(self.regexp, msg.cmd))
|
||||
)
|
||||
|
|
@ -17,9 +17,6 @@
|
|||
import re
|
||||
|
||||
from nemubot.hooks.abstract import Abstract
|
||||
from nemubot.hooks.keywords import NoKeyword
|
||||
from nemubot.hooks.keywords.abstract import Abstract as AbstractKeywords
|
||||
from nemubot.hooks.keywords.dict import Dict as DictKeywords
|
||||
import nemubot.message
|
||||
|
||||
|
||||
|
|
@ -27,64 +24,26 @@ class Message(Abstract):
|
|||
|
||||
"""Class storing hook information, specialized for a generic Message"""
|
||||
|
||||
def __init__(self, call, name=None, regexp=None, channels=list(),
|
||||
server=None, help=None, help_usage=dict(), keywords=NoKeyword(),
|
||||
**kargs):
|
||||
|
||||
Abstract.__init__(self, call=call, **kargs)
|
||||
|
||||
if isinstance(keywords, dict):
|
||||
keywords = DictKeywords(keywords)
|
||||
def __init__(self, call, regexp=None, help=None, **kwargs):
|
||||
super().__init__(call=call, **kwargs)
|
||||
|
||||
assert regexp is None or type(regexp) is str, regexp
|
||||
assert channels is None or type(channels) is list, channels
|
||||
assert server is None or type(server) is str, server
|
||||
assert type(help_usage) is dict, help_usage
|
||||
assert isinstance(keywords, AbstractKeywords), keywords
|
||||
|
||||
self.name = str(name) if name is not None else None
|
||||
self.regexp = regexp
|
||||
self.server = server
|
||||
self.channels = channels
|
||||
self.help = help
|
||||
self.help_usage = help_usage
|
||||
self.keywords = keywords
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "\x03\x02%s\x03\x02%s%s" % (
|
||||
self.name if self.name is not None else "\x03\x1f" + self.regexp + "\x03\x1f" if self.regexp is not None else "",
|
||||
" (restricted to %:%s)" % ((",".join(self.servers) if self.server else "*") + (",".join(self.channels) if self.channels else "*")) if len(self.channels) or len(self.server) else "",
|
||||
": %s" % self.help if self.help is not None else ""
|
||||
)
|
||||
# TODO: find a way to name the feature (like command: help)
|
||||
return self.help if self.help is not None else super().__str__()
|
||||
|
||||
|
||||
def check(self, msg):
|
||||
return not hasattr(msg, "kwargs") or self.keywords.check(msg.kwargs)
|
||||
return super().check(msg)
|
||||
|
||||
|
||||
def match(self, msg, server=None):
|
||||
if not isinstance(msg, nemubot.message.abstract.Abstract):
|
||||
return True
|
||||
|
||||
elif isinstance(msg, nemubot.message.Command):
|
||||
return self.is_matching(msg.cmd, msg.to, server)
|
||||
elif isinstance(msg, nemubot.message.Text):
|
||||
return self.is_matching(msg.message, msg.to, server)
|
||||
else:
|
||||
def match(self, msg):
|
||||
if not isinstance(msg, nemubot.message.text.Text):
|
||||
return False
|
||||
|
||||
|
||||
def is_matching(self, strcmp, receivers=list(), server=None):
|
||||
"""Test if the current hook correspond to the message"""
|
||||
if ((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)))):
|
||||
|
||||
if receivers and self.channels:
|
||||
for receiver in receivers:
|
||||
if receiver in self.channels:
|
||||
return True
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
return self.regexp is None or re.match(self.regexp, msg.message)
|
||||
|
|
|
|||
|
|
@ -14,21 +14,6 @@
|
|||
# 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/>.
|
||||
|
||||
def convert_legacy_store(old):
|
||||
if old == "cmd_hook" or old == "cmd_rgxp" or old == "cmd_default":
|
||||
return "in_Command"
|
||||
elif old == "ask_hook" or old == "ask_rgxp" or old == "ask_default":
|
||||
return "in_DirectAsk"
|
||||
elif old == "msg_hook" or old == "msg_rgxp" or old == "msg_default":
|
||||
return "in_Text"
|
||||
elif old == "all_post":
|
||||
return "post"
|
||||
elif old == "all_pre":
|
||||
return "pre"
|
||||
else:
|
||||
return old
|
||||
|
||||
|
||||
class ModuleContext:
|
||||
|
||||
def __init__(self, context, module):
|
||||
|
|
@ -60,11 +45,9 @@ class ModuleContext:
|
|||
self.data = context.datastore.load(module_name)
|
||||
|
||||
def add_hook(store, hook):
|
||||
store = convert_legacy_store(store)
|
||||
self.hooks.append((store, hook))
|
||||
return context.treater.hm.add_hook(hook, store)
|
||||
def del_hook(store, hook):
|
||||
store = convert_legacy_store(store)
|
||||
self.hooks.remove((store, hook))
|
||||
return context.treater.hm.del_hook(hook, store)
|
||||
def call_hook(store, msg):
|
||||
|
|
@ -98,10 +81,8 @@ class ModuleContext:
|
|||
self.data = module_state.ModuleState("nemubotstate")
|
||||
|
||||
def add_hook(store, hook):
|
||||
store = convert_legacy_store(store)
|
||||
self.hooks.append((store, hook))
|
||||
def del_hook(store, hook):
|
||||
store = convert_legacy_store(store)
|
||||
self.hooks.remove((store, hook))
|
||||
def call_hook(store, msg):
|
||||
# TODO: what can we do here?
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue