From 9874f79b498e1f8ae5ebec9a240963e908b645b0 Mon Sep 17 00:00:00 2001 From: jesopo Date: Fri, 31 Aug 2018 12:55:52 +0100 Subject: [PATCH] Give modules event objects with "context"s, to facilitate purging all the event hooks for a module --- EventManager.py | 122 +++++++++++++++++++++++++----------- IRCBot.py | 22 ++++--- IRCLineHandler.py | 119 ++++++++++++++++------------------- IRCServer.py | 17 ++--- ModuleManager.py | 40 ++++-------- Timer.py | 8 ++- modules/accept_invite.py | 5 +- modules/admin.py | 8 +-- modules/auto_mode.py | 8 +-- modules/bitcoin.py | 4 +- modules/bitly.py | 9 +-- modules/books.py | 6 +- modules/channel_op.py | 28 ++++----- modules/channel_save.py | 9 ++- modules/check_mode.py | 5 +- modules/coins.py | 18 +++--- modules/commands.py | 41 ++++++------ modules/ctcp.py | 6 +- modules/define.py | 4 +- modules/dns.py | 4 +- modules/ducks.py | 27 ++++---- modules/geoip.py | 4 +- modules/google.py | 4 +- modules/hash.py | 4 +- modules/haveibeenpwned.py | 4 +- modules/ids.py | 6 +- modules/imdb.py | 4 +- modules/in.py | 6 +- modules/join.py | 8 +-- modules/karma.py | 17 ++--- modules/lastfm.py | 6 +- modules/nickname_aliases.py | 10 +-- modules/nickserv.py | 6 +- modules/nr.py | 18 +++--- modules/perform.py | 4 +- modules/permissions.py | 20 +++--- modules/pong.py | 5 +- modules/print_activity.py | 34 +++++----- modules/quit.py | 4 +- modules/quotes.py | 10 +-- modules/random_number.py | 6 +- modules/sasl.py | 10 +-- modules/sed.py | 13 ++-- modules/seen.py | 6 +- modules/set.py | 17 ++--- modules/signals.py | 8 ++- modules/soundcloud.py | 4 +- modules/spotify.py | 4 +- modules/stats.py | 6 +- modules/strax.py | 4 +- modules/telegram.py | 11 ++-- modules/tfl.py | 14 ++--- modules/thesaurus.py | 4 +- modules/title.py | 50 +++++++-------- modules/to.py | 6 +- modules/todo.py | 8 +-- modules/trakt.py | 6 +- modules/translate.py | 4 +- modules/twitter.py | 4 +- modules/upc.py | 4 +- modules/urbandictionary.py | 4 +- modules/weather.py | 4 +- modules/wikipedia.py | 4 +- modules/wolframalpha.py | 6 +- modules/words.py | 12 ++-- modules/youtube.py | 11 ++-- start.py | 2 +- 67 files changed, 476 insertions(+), 440 deletions(-) diff --git a/EventManager.py b/EventManager.py index 66006934..4190af05 100644 --- a/EventManager.py +++ b/EventManager.py @@ -1,10 +1,13 @@ -import time, traceback +import itertools, time, traceback PRIORITY_URGENT = 0 PRIORITY_HIGH = 1 PRIORITY_MEDIUM = 2 PRIORITY_LOW = 3 +DEFAULT_PRIORITY = PRIORITY_LOW +DEFAULT_DELIMITER = "." + class Event(object): def __init__(self, bot, name, **kwargs): self.bot = bot @@ -21,7 +24,7 @@ class Event(object): self.eaten = True class EventCallback(object): - def __init__(self, function, bot, priority, **kwargs): + def __init__(self, function, bot, priority, kwargs): self.function = function self.bot = bot self.priority = priority @@ -50,6 +53,28 @@ class MultipleEventHook(object): returns.append(event_hook.call(**kwargs)) return returns +class EventHookContext(object): + def __init__(self, parent, context): + self._parent = parent + self.context = context + def hook(self, function, priority=DEFAULT_PRIORITY, **kwargs): + self._parent._context_hook(self.context, function, priority, kwargs) + def on(self, subevent, *extra_subevents, delimiter=DEFAULT_DELIMITER): + return self._parent._context_on(self.context, subevent, + extra_subevents, delimiter) + def call_for_result(self, default=None, **kwargs): + return self._parent.call_for_result(default, **kwargs) + def assure_call(self, **kwargs): + self._parent.assure_call(**kwargs) + def call(self, **kwargs): + return self._parent.call(**kwargs) + def call_limited(self, maximum, **kwargs): + return self._parent.call_limited(maximum, **kwargs) + def get_hooks(self): + return self._parent.get_hooks() + def get_children(self): + return self._parent.get_children() + class EventHook(object): def __init__(self, bot, name=None, parent=None): self.bot = bot @@ -57,10 +82,9 @@ class EventHook(object): self.parent = parent self._children = {} self._hooks = [] - self._hook_notify = None - self._child_notify = None - self._call_notify = None self._stored_events = [] + self._context_hooks = {} + self._current_context = None def _make_event(self, kwargs): return Event(self.bot, self.name, **kwargs) @@ -71,14 +95,28 @@ class EventHook(object): while not parent == None and not parent.name == None: path.append(parent.name) parent = parent.parent - return ".".join(path[::-1]) + return DEFAULT_DELIMITER.join(path[::-1]) - def hook(self, function, priority=PRIORITY_LOW, replay=False, **kwargs): - callback = EventCallback(function, self.bot, priority, **kwargs) - if self._hook_notify: - self._hook_notify(self, callback) - self._hooks.append(callback) - self._hooks.sort(key=lambda x: x.priority) + def new_context(self, context): + return EventHookContext(self, context) + + def hook(self, function, priority=DEFAULT_PRIORITY, replay=False, + **kwargs): + self._hook(function, None, priority, replay, kwargs) + def _context_hook(self, context, function, priority, kwargs): + self._hook(function, context, priority, False, kwargs) + def _hook(self, function, context, priority, replay, kwargs): + callback = EventCallback(function, self.bot, priority, kwargs) + + if context == None: + self._hooks.append(callback) + hooks = self._hooks + else: + if not context in self._context_hooks: + self._context_hooks[context] = [] + self._context_hooks[context].append(callback) + hooks = self._context_hooks[context] + hooks.sort(key=lambda x: x.priority) if replay and not self._stored_events == None: for kwargs in self._stored_events: @@ -88,24 +126,37 @@ class EventHook(object): def _unhook(self, hook): self._hooks.remove(hook) - def on(self, subevent, *extra_subevents, delimiter="."): + def on(self, subevent, *extra_subevents, delimiter=DEFAULT_DELIMITER): + return self._on(subevent, extra_subevents, None, delimiter) + def _context_on(self, context, subevent, extra_subevents, + delimiter=DEFAULT_DELIMITER): + return self._on(subevent, extra_subevents, context, delimiter) + def _on(self, subevent, extra_subevents, context, delimiter): if delimiter in subevent: event_chain = subevent.split(delimiter) event_obj = self for event_name in event_chain: event_obj = event_obj.get_child(event_name) + if not context == None: + event_obj = event_obj.new_context(context) return event_obj if extra_subevents: multiple_event_hook = MultipleEventHook() for extra_subevent in (subevent,)+extra_subevents: - multiple_event_hook._add(self.get_child(extra_subevent)) + child = self.get_child(extra_subevent) + if not context == None: + child = child.new_context(context) + multiple_event_hook._add(child) return multiple_event_hook - return self.get_child(subevent) + child = self.get_child(subevent) + if not context == None: + child = child.new_context(context) + return child - def call_for_result(self, default=None, max=None, **kwargs): - results = self.call(max=max, **kwargs) + def call_for_result(self, default=None, **kwargs): + results = self.call_limited(0, **kwargs) return default if not len(results) else results[0] def assure_call(self, **kwargs): if not self._stored_events == None: @@ -123,15 +174,10 @@ class EventHook(object): start = time.monotonic() event = self._make_event(kwargs) - if self._call_notify: - self._call_notify(self, event) - called = 0 returns = [] - for hook in self._hooks: - if maximum and called == maximum: - break - if event.eaten: + for hook in self.get_hooks(): + if (maximum and called == maximum) or event.eaten: break try: returns.append(hook.call(event)) @@ -155,28 +201,30 @@ class EventHook(object): if not child_name_lower in self._children: self._children[child_name_lower] = EventHook(self.bot, child_name_lower, self) - if self._child_notify: - self._child_notify(self, self._children[ - child_name_lower]) return self._children[child_name_lower] - def remove_child(self, child_name): child_name_lower = child_name.lower() if child_name_lower in self._children: del self._children[child_name_lower] + def get_children(self): + return self._children.keys() + def check_purge(self): if len(self._hooks) == 0 and len(self._children ) == 0 and not self.parent == None: self.parent.remove_child(self.name) self.parent.check_purge() + def remove_context(self, context): + del self._context_hooks[context] + def has_context(self, context): + return context in self._context_hooks + def purge_context(self, context): + if self.has_context(context): + self.remove_context(context) + for child in self.get_children(): + child.purge_context(context) + def get_hooks(self): - return self._hooks - def get_children(self): - return self._children.keys() - def set_hook_notify(self, handler): - self._hook_notify = handler - def set_child_notify(self, handler): - self._child_notify = handler - def set_call_notify(self, handler): - self._call_notify = handler + return self._hooks + list(itertools.chain.from_iterable( + self._context_hooks.values())) diff --git a/IRCBot.py b/IRCBot.py index 185abf83..5a5ed286 100644 --- a/IRCBot.py +++ b/IRCBot.py @@ -1,4 +1,4 @@ -import os, select, sys, threading, time, traceback +import os, select, sys, threading, time, traceback, uuid import EventManager, IRCLineHandler, IRCLogging, IRCServer import ModuleManager, Timer @@ -13,21 +13,21 @@ class Bot(object): self.servers = {} self.running = True self.poll = select.epoll() - self.modules = ModuleManager.ModuleManager(self) - self.events = EventManager.EventHook(self) + self._events = EventManager.EventHook(self) + self.modules = ModuleManager.ModuleManager(self, self._events) self.log = IRCLogging.Log(self) - self.line_handler = IRCLineHandler.LineHandler(self) + self.line_handler = IRCLineHandler.LineHandler(self, self._events) self.timers = [] - self.events.on("timer").on("reconnect").hook(self.reconnect) - self.events.on("boot").on("done").hook(self.setup_timers) + self._events.on("timer").on("reconnect").hook(self.reconnect) + self._events.on("boot").on("done").hook(self.setup_timers) def add_server(self, id, hostname, port, password, ipv4, tls, nickname, username, realname, connect=False): - new_server = IRCServer.Server(id, hostname, port, password, - ipv4, tls, nickname, username, realname, self) + new_server = IRCServer.Server(self, self._events, id, hostname, + port, password, ipv4, tls, nickname, username, realname) if not new_server.get_setting("connect", True): return - self.events.on("new").on("server").call(server=new_server) + self._events.on("new").on("server").call(server=new_server) if connect and new_server.get_setting("connect", True): self.connect(new_server) return new_server @@ -55,7 +55,9 @@ class Bot(object): self.del_setting("timer-%s" % timer.id) def add_timer(self, event_name, delay, next_due=None, id=None, persist=True, **kwargs): - timer = Timer.Timer(self, event_name, delay, next_due, **kwargs) + id = id or uuid.uuid4().hex + timer = Timer.Timer(id, self, self._events, event_name, delay, + next_due, **kwargs) if id: timer.id = id elif persist: diff --git a/IRCLineHandler.py b/IRCLineHandler.py index 1deadb3b..e8a27c74 100644 --- a/IRCLineHandler.py +++ b/IRCLineHandler.py @@ -8,47 +8,38 @@ RE_CHANTYPES = re.compile(r"\bCHANTYPES=(\W+)(?:\b|$)") RE_MODES = re.compile(r"[-+]\w+") class LineHandler(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("raw").on("PING").hook(self.ping) + self.events = events + events.on("raw").on("PING").hook(self.ping) - bot.events.on("raw").on("001").hook(self.handle_001, - default_event=True) - bot.events.on("raw").on("005").hook(self.handle_005) - bot.events.on("raw").on("311").hook(self.handle_311, - default_event=True) - bot.events.on("raw").on("332").hook(self.handle_332) - bot.events.on("raw").on("333").hook(self.handle_333) - bot.events.on("raw").on("353").hook(self.handle_353, - default_event=True) - bot.events.on("raw").on("366").hook(self.handle_366, - default_event=True) - bot.events.on("raw").on("421").hook(self.handle_421, - default_event=True) - bot.events.on("raw").on("352").hook(self.handle_352, - default_event=True) - bot.events.on("raw").on("324").hook(self.handle_324, - default_event=True) - bot.events.on("raw").on("329").hook(self.handle_329, - default_event=True) - bot.events.on("raw").on("433").hook(self.handle_433, - default_event=True) - bot.events.on("raw").on("477").hook(self.handle_477, - default_event=True) + events.on("raw").on("001").hook(self.handle_001, default_event=True) + events.on("raw").on("005").hook(self.handle_005) + events.on("raw").on("311").hook(self.handle_311, default_event=True) + events.on("raw").on("332").hook(self.handle_332) + events.on("raw").on("333").hook(self.handle_333) + events.on("raw").on("353").hook(self.handle_353, default_event=True) + events.on("raw").on("366").hook(self.handle_366, default_event=True) + events.on("raw").on("421").hook(self.handle_421, default_event=True) + events.on("raw").on("352").hook(self.handle_352, default_event=True) + events.on("raw").on("324").hook(self.handle_324, default_event=True) + events.on("raw").on("329").hook(self.handle_329, default_event=True) + events.on("raw").on("433").hook(self.handle_433, default_event=True) + events.on("raw").on("477").hook(self.handle_477, default_event=True) - bot.events.on("raw").on("JOIN").hook(self.join) - bot.events.on("raw").on("PART").hook(self.part) - bot.events.on("raw").on("QUIT").hook(self.quit) - bot.events.on("raw").on("NICK").hook(self.nick) - bot.events.on("raw").on("MODE").hook(self.mode) - bot.events.on("raw").on("KICK").hook(self.kick) - bot.events.on("raw").on("INVITE").hook(self.invite) - bot.events.on("raw").on("TOPIC").hook(self.topic) - bot.events.on("raw").on("PRIVMSG").hook(self.privmsg) - bot.events.on("raw").on("NOTICE").hook(self.notice) + events.on("raw").on("JOIN").hook(self.join) + events.on("raw").on("PART").hook(self.part) + events.on("raw").on("QUIT").hook(self.quit) + events.on("raw").on("NICK").hook(self.nick) + events.on("raw").on("MODE").hook(self.mode) + events.on("raw").on("KICK").hook(self.kick) + events.on("raw").on("INVITE").hook(self.invite) + events.on("raw").on("TOPIC").hook(self.topic) + events.on("raw").on("PRIVMSG").hook(self.privmsg) + events.on("raw").on("NOTICE").hook(self.notice) - bot.events.on("raw").on("CAP").hook(self.cap) - bot.events.on("raw").on("authenticate").hook(self.authenticate) + events.on("raw").on("CAP").hook(self.cap) + events.on("raw").on("authenticate").hook(self.authenticate) def handle(self, server, line): original_line = line @@ -66,7 +57,7 @@ class LineHandler(object): line = line[:-1] args = line.split(" ") - hooks = self.bot.events.on("raw").on(command).get_hooks() + hooks = self.events.on("raw").on(command).get_hooks() default_event = False for hook in hooks: if hook.kwargs.get("default_event", False): @@ -74,15 +65,15 @@ class LineHandler(object): break #server, prefix, command, args, arbitrary - self.bot.events.on("raw").on(command).call(server=server, + self.events.on("raw").on(command).call(server=server, prefix=prefix, args=args, arbitrary=arbitrary) if default_event or not hooks: if command.isdigit(): - self.bot.events.on("received").on("numeric").on(command + self.events.on("received").on("numeric").on(command ).call(line=original_line, server=server, line_split=original_line.split(" "), number=command) else: - self.bot.events.on("received").on(command).call( + self.events.on("received").on(command).call( line=original_line, line_split=original_line.split(" "), command=command, server=server) @@ -116,7 +107,7 @@ class LineHandler(object): match = re.search(RE_CHANTYPES, isupport_line) if match: event["server"].channel_types = list(match.group(1)) - self.bot.events.on("received").on("numeric").on("005").call( + self.events.on("received").on("numeric").on("005").call( isupport=isupport_line, server=event["server"]) # whois respose (nickname, username, realname, hostname) @@ -135,7 +126,7 @@ class LineHandler(object): channel = event["server"].get_channel(event["args"][1]) channel.set_topic(event["arbitrary"]) - self.bot.events.on("received").on("numeric").on("332" + self.events.on("received").on("numeric").on("332" ).call(channel=channel, server=event["server"], topic=event["arbitrary"]) @@ -147,7 +138,7 @@ class LineHandler(object): channel = event["server"].get_channel(event["args"][0]) channel.set_topic(event["arbitrary"]) - self.bot.events.on("received").on("topic").call(channel=channel, + self.events.on("received").on("topic").call(channel=channel, server=event["server"], topic=event["arbitrary"], user=user) # on-join channel topic set by/at @@ -162,7 +153,7 @@ class LineHandler(object): channel.set_topic_setter(nickname, username, hostname) channel.set_topic_time(topic_time) - self.bot.events.on("received").on("numeric").on("333" + self.events.on("received").on("numeric").on("333" ).call(channel=channel, setter=nickname, set_at=topic_time, server=event["server"]) @@ -202,12 +193,12 @@ class LineHandler(object): user.hostname = hostname channel.add_user(user) user.join_channel(channel) - self.bot.events.on("received").on("join").call(channel=channel, + self.events.on("received").on("join").call(channel=channel, user=user, server=event["server"]) else: if channel.name in event["server"].attempted_join: del event["server"].attempted_join[channel.name] - self.bot.events.on("self").on("join").call(channel=channel, + self.events.on("self").on("join").call(channel=channel, server=event["server"]) channel.send_mode() @@ -220,7 +211,7 @@ class LineHandler(object): if not event["server"].is_own_nickname(nickname): user = event["server"].get_user(nickname) - self.bot.events.on("received").on("part").call(channel=channel, + self.events.on("received").on("part").call(channel=channel, reason=reason, user=user, server=event["server"]) channel.remove_user(user) user.part_channel(channel) @@ -228,7 +219,7 @@ class LineHandler(object): event["server"].remove_user(user) else: event["server"].remove_channel(channel) - self.bot.events.on("self").on("part").call(channel=channel, + self.events.on("self").on("part").call(channel=channel, reason=reason, server=event["server"]) # unknown command sent by us, oops! @@ -244,7 +235,7 @@ class LineHandler(object): if not event["server"].is_own_nickname(nickname): user = event["server"].get_user(nickname) event["server"].remove_user(user) - self.bot.events.on("received").on("quit").call(reason=reason, + self.events.on("received").on("quit").call(reason=reason, user=user, server=event["server"]) else: event["server"].disconnect() @@ -252,13 +243,13 @@ class LineHandler(object): # the server is telling us about its capabilities! def cap(self, event): capabilities = (event["arbitrary"] or "").split(" ") - self.bot.events.on("received").on("cap").call( + self.events.on("received").on("cap").call( subcommand=event["args"][1], capabilities=capabilities, server=event["server"]) # the server is asking for authentication def authenticate(self, event): - self.bot.events.on("received").on("authenticate").call( + self.events.on("received").on("authenticate").call( message=event["args"][0], server=event["server"]) # someone has changed their nickname @@ -271,13 +262,13 @@ class LineHandler(object): old_nickname = user.nickname user.set_nickname(new_nickname) event["server"].change_user_nickname(old_nickname, new_nickname) - self.bot.events.on("received").on("nick").call( + self.events.on("received").on("nick").call( new_nickname=new_nickname, old_nickname=old_nickname, user=user, server=event["server"]) else: old_nickname = event["server"].nickname event["server"].set_own_nickname(new_nickname) - self.bot.events.on("self").on("nick").call( + self.events.on("self").on("nick").call( server=event["server"], new_nickname=new_nickname, old_nickname=old_nickname) @@ -303,7 +294,7 @@ class LineHandler(object): channel.change_mode(remove, mode, args.pop(0)) else: args.pop(0) - self.bot.events.on("received").on("mode").call(modes=modes, + self.events.on("received").on("mode").call(modes=modes, mode_args=args, channel=channel, server=event["server"]) elif event["server"].is_own_nickname(target): modes = RE_MODES.findall(event["arbitrary"] or args[1]) @@ -311,7 +302,7 @@ class LineHandler(object): remove = chunk[0] == "-" for mode in chunk[1:]: event["server"].change_own_mode(remove, mode) - self.bot.events.on("self").on("mode").call(modes=modes, + self.events.on("self").on("mode").call(modes=modes, server=event["server"]) # I've been invited somewhere @@ -320,7 +311,7 @@ class LineHandler(object): event["prefix"]) target_channel = event["arbitrary"] user = event["server"].get_user(nickname) - self.bot.events.on("received").on("invite").call( + self.events.on("received").on("invite").call( user=user, target_channel=target_channel, server=event["server"]) @@ -337,12 +328,12 @@ class LineHandler(object): message = message.replace("\01ACTION ", "", 1)[:-1] if target[0] in event["server"].channel_types: channel = event["server"].get_channel(event["args"][0]) - self.bot.events.on("received").on("message").on("channel").call( + self.events.on("received").on("message").on("channel").call( user=user, message=message, message_split=message_split, channel=channel, action=action, server=event["server"]) channel.buffer.add_line(user.nickname, message, action) elif event["server"].is_own_nickname(target): - self.bot.events.on("received").on("message").on("private").call( + self.events.on("received").on("message").on("private").call( user=user, message=message, message_split=message_split, action=action, server=event["server"]) user.buffer.add_line(user.nickname, message, action) @@ -355,18 +346,18 @@ class LineHandler(object): message_split = message.split(" ") target = event["args"][0] if nickname == event["server"].name or target == "*": - self.bot.events.on("received.server-notice").call( + self.events.on("received.server-notice").call( message=message, message_split=message_split, server=event["server"]) else: user = event["server"].get_user(nickname) if target[0] in event["server"].channel_types: channel = event["server"].get_channel(target) - self.bot.events.on("received.notice.channel").call( + self.events.on("received.notice.channel").call( message=message, message_split=message_split, user=user, server=event["server"], channel=channel) elif event["server"].is_own_nickname(target): - self.bot.events.on("received.notice.private").call( + self.events.on("received.notice.private").call( message=message, message_split=message_split, user=user, server=event["server"]) @@ -413,9 +404,9 @@ class LineHandler(object): if not event["server"].is_own_nickname(target): target_user = event["server"].get_user(target) - self.bot.events.on("received").on("kick").call(channel=channel, + self.events.on("received").on("kick").call(channel=channel, reason=reason, target_user=target_user, user=user, server=event["server"]) else: - self.bot.events.on("self").on("kick").call(channel=channel, + self.events.on("self").on("kick").call(channel=channel, reason=reason, user=user, server=event["server"]) diff --git a/IRCServer.py b/IRCServer.py index 05cf3351..5ed33baf 100644 --- a/IRCServer.py +++ b/IRCServer.py @@ -11,10 +11,11 @@ if hasattr(ssl, "PROTOCOL_TLS"): OUR_TLS_PROTOCOL = ssl.PROTOCOL_TLS class Server(object): - def __init__(self, id, hostname, port, password, ipv4, tls, - nickname, username, realname, bot): + def __init__(self, bot, events, id, hostname, port, password, ipv4, + tls, nickname, username, realname): self.connected = False self.bot = bot + self.events = events self.id = id self.target_hostname = hostname self.port = port @@ -65,7 +66,7 @@ class Server(object): context.options |= ssl.OP_NO_TLSv1 self.socket = context.wrap_socket(self.socket) self.cached_fileno = self.socket.fileno() - self.bot.events.on("timer").on("rejoin").hook(self.try_rejoin) + self.events.on("timer").on("rejoin").hook(self.try_rejoin) def __repr__(self): return "IRCServer.Server(%s)" % self.__str__() @@ -78,7 +79,7 @@ class Server(object): def connect(self): self.socket.connect((self.target_hostname, self.port)) - self.bot.events.on("preprocess.connect").call(server=self) + self.events.on("preprocess.connect").call(server=self) if self.password: self.send_pass(self.password) @@ -137,7 +138,7 @@ class Server(object): if not self.has_user(nickname): user_id = self.get_user_id(nickname) new_user = IRCUser.User(nickname, user_id, self, self.bot) - self.bot.events.on("new").on("user").call( + self.events.on("new").on("user").call( user=new_user, server=self) self.users[new_user.nickname_lower] = new_user self.new_users.add(new_user) @@ -162,7 +163,7 @@ class Server(object): channel_id = self.get_channel_id(channel_name) new_channel = IRCChannel.Channel(channel_name, channel_id, self, self.bot) - self.bot.events.on("new").on("channel").call( + self.events.on("new").on("channel").call( channel=new_channel, server=self) self.channels[new_channel.name] = new_channel return self.channels[channel_name.lower()] @@ -311,13 +312,13 @@ class Server(object): if self.has_channel(target): channel = self.get_channel(target) channel.buffer.add_line(None, message, action, True) - self.bot.events.on("self").on("message").on("channel").call( + self.events.on("self").on("message").on("channel").call( message=full_message, message_split=full_message_split, channel=channel, action=action, server=self) else: user = self.get_user(target) user.buffer.add_line(None, message, action, True) - self.bot.events.on("self").on("message").on("private").call( + self.events.on("self").on("message").on("private").call( message=full_message, message_split=full_message_split, user=user, action=action, server=self) diff --git a/ModuleManager.py b/ModuleManager.py index e601ce9e..812edb71 100644 --- a/ModuleManager.py +++ b/ModuleManager.py @@ -1,8 +1,9 @@ -import gc, glob, imp, inspect, os, sys +import gc, glob, imp, inspect, os, sys, uuid class ModuleManager(object): - def __init__(self, bot, directory="modules"): + def __init__(self, bot, events, directory="modules"): self.bot = bot + self.events = events self.directory = directory self.modules = {} self.waiting_requirement = {} @@ -39,17 +40,22 @@ class ModuleManager(object): return None else: break - import_name = "bitbot_%s" % name - module = imp.load_source(import_name, filename) + module = imp.load_source(name, filename) + if not hasattr(module, "Module"): raise ImportError("module '%s' doesn't have a Module class.") if not inspect.isclass(module.Module): raise ImportError("module '%s' has a Module attribute but it is not a class.") - module_object = module.Module(self.bot) + + event_context = uuid.uuid4() + module_object = module.Module(self.bot, self.events.new_context( + event_context)) if not hasattr(module_object, "_name"): module_object._name = name.title() + module_object._event_context = event_context module_object._is_unloaded = False - module_object._import_name = import_name + module_object._import_name = name + assert not module_object._name in self.modules, ( "module name '%s' attempted to be used twice.") return module_object @@ -62,7 +68,7 @@ class ModuleManager(object): sys.stderr.write("module '%s' not loaded: Could not resolve import.\n" % filename) return if module: - self.modules[module._name] = module + self.modules[module._import_name] = module if name in self.waiting_requirement: for filename in self.waiting_requirement: self.load_module(filename) @@ -74,23 +80,3 @@ class ModuleManager(object): for filename in self.list_modules(): if whitelist == None or filename in whitelist: self.load_module(filename) - - def unload_module(self, module): - # this is such a bad idea - module._is_unloaded = True - self.unhook_check(self.bot.events) - if hasattr(module, "_cleanup"): - module._cleanup() - del sys.modules[module._import_name] - del self.modules[module._name] - del module - gc.collect() - - def unhook_check(self, event): - for hook in event.get_hooks(): - if hasattr(hook.function, "__self__") and hasattr( - hook.function.__self__, "_is_unloaded" - ) and hook.function.__self__._is_unloaded: - event._unhook(hook) - for child in event.get_children(): - self.unhook_check(event.get_child(child)) diff --git a/Timer.py b/Timer.py index 789e7e37..7ac83630 100644 --- a/Timer.py +++ b/Timer.py @@ -1,9 +1,11 @@ import time, uuid class Timer(object): - def __init__(self, bot, event_name, delay, next_due=None, **kwargs): - self.id = uuid.uuid4().hex + def __init__(self, id, bot, events, event_name, delay, + next_due=None, **kwargs): + self.id = id self.bot = bot + self.events = events self.event_name = event_name self.delay = delay if next_due: @@ -26,7 +28,7 @@ class Timer(object): def call(self): self._done = True self.call_count +=1 - self.bot.events.on("timer").on(self.event_name).call( + self.events.on("timer").on(self.event_name).call( timer=self, **self.kwargs) def redo(self): diff --git a/modules/accept_invite.py b/modules/accept_invite.py index 57ba9d70..e25aea76 100644 --- a/modules/accept_invite.py +++ b/modules/accept_invite.py @@ -1,9 +1,8 @@ class Module(object): - def __init__(self, bot): - bot.events.on("received").on("invite").hook( - self.on_invite) + def __init__(self, bot, events): + events.on("received").on("invite").hook(self.on_invite) def on_invite(self, event): if event["server"].get_setting("accept-invites", True): diff --git a/modules/admin.py b/modules/admin.py index 400c54df..5578febe 100644 --- a/modules/admin.py +++ b/modules/admin.py @@ -1,16 +1,16 @@ class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("command").on("changenickname" + events.on("received").on("command").on("changenickname" ).hook(self.change_nickname, permission="changenickname", min_args=1, help="Change my nickname", usage="") - bot.events.on("received").on("command").on("raw" + events.on("received").on("command").on("raw" ).hook(self.raw, permission="raw", min_args=1, help="Send a raw IRC line through the bot", usage="") - bot.events.on("received").on("command").on("part" + events.on("received").on("command").on("part" ).hook(self.part, permission="part", min_args=1, help="Part from a channel", usage="<#channel>") diff --git a/modules/auto_mode.py b/modules/auto_mode.py index 2c33f260..3e800591 100644 --- a/modules/auto_mode.py +++ b/modules/auto_mode.py @@ -1,16 +1,16 @@ import Utils class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("postboot").on("configure").on( + events.on("postboot").on("configure").on( "channelset").assure_call(setting="automode", help="Disable/Enable automode", validate=Utils.bool_or_none) - bot.events.on("channel").on("mode").hook(self.on_mode) - bot.events.on("received").on("join").hook(self.on_join) + events.on("channel").on("mode").hook(self.on_mode) + events.on("received").on("join").hook(self.on_join) def on_mode(self, event): if event["channel"].get_setting("automode", False): diff --git a/modules/bitcoin.py b/modules/bitcoin.py index 17408322..f15c5266 100644 --- a/modules/bitcoin.py +++ b/modules/bitcoin.py @@ -2,9 +2,9 @@ import Utils class Module(object): _name = "BTC" - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("command").on("btc").hook( + events.on("received").on("command").on("btc").hook( self.btc, help="Get the exchange rate of bitcoins", usage="[currency]") diff --git a/modules/bitly.py b/modules/bitly.py index f31ca347..05489fb0 100644 --- a/modules/bitly.py +++ b/modules/bitly.py @@ -7,10 +7,11 @@ URL_BITLYSHORTEN = "https://api-ssl.bitly.com/v3/shorten" REGEX_URL = re.compile("https?://", re.I) class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("get").on("shortlink").hook(self.shortlink) - bot.events.on("received").on("command").on("shorten" + self.events = events + events.on("get").on("shortlink").hook(self.shortlink) + events.on("received").on("command").on("shorten" ).hook(self.shorten, min_args=1, help="Shorten a URL.", usage="") @@ -25,7 +26,7 @@ class Module(object): return data["data"]["url"] def shorten(self, event): - link = self.bot.events.on("get").on("shortlink" + link = self.events.on("get").on("shortlink" ).call_for_result(url=event["args"]) if link: event["stdout"].write("Short URL: %s" % link) diff --git a/modules/books.py b/modules/books.py index 5f7c0627..9c94c656 100644 --- a/modules/books.py +++ b/modules/books.py @@ -7,12 +7,12 @@ REGEX_BOOKID = re.compile("id=([\w\-]+)") class Module(object): _name = "ISBN" - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("command").on("isbn").hook( + events.on("received").on("command").on("isbn").hook( self.isbn, help="Get book information from a provided ISBN", min_args=1, usage="") - bot.events.on("received").on("command").on("book").hook( + events.on("received").on("command").on("book").hook( self.book, help="Get book information from a provided title", min_args=1, usage="") diff --git a/modules/channel_op.py b/modules/channel_op.py index b488f224..9e20d693 100644 --- a/modules/channel_op.py +++ b/modules/channel_op.py @@ -2,57 +2,57 @@ import Utils class Module(object): _name = "Channel Op" - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("command").on("kick", "k" + events.on("received").on("command").on("kick", "k" ).hook(self.kick, channel_only=True, require_mode="o", min_args=1, help="Kick a user from the channel", usage=" [reason]") - bot.events.on("received").on("command").on("ban" + events.on("received").on("command").on("ban" ).hook(self.ban, channel_only=True, require_mode="o", min_args=1, help="Ban a user/hostmask from the channel", usage="") - bot.events.on("received").on("command").on("unban" + events.on("received").on("command").on("unban" ).hook(self.unban, channel_only=True, require_mode="o", min_args=1, help="Unban a user/hostmask from the channel", usage="") - bot.events.on("received").on("command").on("kickban", "kb" + events.on("received").on("command").on("kickban", "kb" ).hook(self.kickban, channel_only=True, require_mode="o", min_args=1, help="Kickban a user from the channel", usage=" [reason]") - bot.events.on("received").on("command").on("op" + events.on("received").on("command").on("op" ).hook(self.op, channel_only=True, require_mode="o", help="Give +o to a user", usage="[nickname]") - bot.events.on("received").on("command").on("deop" + events.on("received").on("command").on("deop" ).hook(self.deop, channel_only=True, require_mode="o", help="Take +o from a user", usage="[nickname]") - bot.events.on("received").on("command").on("voice" + events.on("received").on("command").on("voice" ).hook(self.voice, channel_only=True, require_mode="o", help="Give +v to a user", usage="[nickname]") - bot.events.on("received").on("command").on("devoice" + events.on("received").on("command").on("devoice" ).hook(self.devoice, channel_only=True, require_mode="o", help="Take +v from a user", usage="[nickname]") - bot.events.on("received").on("message").on("channel").hook( + events.on("received").on("message").on("channel").hook( self.highlight_spam) - bot.events.on("postboot").on("configure").on( + events.on("postboot").on("configure").on( "channelset").assure_call(setting="highlight-spam-threshold", help="Set the number of nicknames in a message that " "qualifies as spam", validate=Utils.int_or_none) - bot.events.on("postboot").on("configure").on( + events.on("postboot").on("configure").on( "channelset").assure_call(setting="highlight-spam-protection", help="Enable/Disable highlight spam protection", validate=Utils.bool_or_none) - bot.events.on("postboot").on("configure").on( + events.on("postboot").on("configure").on( "channelset").assure_call(setting="highlight-spam-ban", help="Enable/Disable banning highlight spammers " "instead of just kicking", validate=Utils.bool_or_none) - bot.events.on("postboot").on("configure").on( + events.on("postboot").on("configure").on( "channelset").assure_call(setting="ban-format", help="Set ban format ($n = nick, $u = username, $h = hostname)") diff --git a/modules/channel_save.py b/modules/channel_save.py index c70d8751..afbd4200 100644 --- a/modules/channel_save.py +++ b/modules/channel_save.py @@ -1,11 +1,10 @@ class Module(object): - def __init__(self, bot): - bot.events.on("received.numeric.001").hook( - self.on_connect) - bot.events.on("self.join").hook(self.on_join) - bot.events.on("self.kick").hook(self.on_kick) + def __init__(self, bot, events): + events.on("received.numeric.001").hook(self.on_connect) + events.on("self.join").hook(self.on_join) + events.on("self.kick").hook(self.on_kick) def on_connect(self, event): channels = event["server"].get_setting("autojoin", []) diff --git a/modules/check_mode.py b/modules/check_mode.py index a7a8e788..4fb2b783 100644 --- a/modules/check_mode.py +++ b/modules/check_mode.py @@ -1,10 +1,9 @@ class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("preprocess").on("command").hook( - self.preprocess_command) + events.on("preprocess").on("command").hook(self.preprocess_command) def preprocess_command(self, event): if event["is_channel"] and event["hook"].kwargs.get( diff --git a/modules/coins.py b/modules/coins.py index 4fa0377e..307f171f 100644 --- a/modules/coins.py +++ b/modules/coins.py @@ -26,26 +26,26 @@ THIRD_COLUMN = list(range(1, 37))[2::3] REGEX_STREET = re.compile("street([1-9]|1[0-2])$") class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received.command.coins").hook(self.coins, + events.on("received.command.coins").hook(self.coins, help="Show how many coins you have") - bot.events.on("received").on("command").on("resetcoins").hook( + events.on("received").on("command").on("resetcoins").hook( self.reset_coins, permission="resetcoins", min_args=1, help= "Reset a specified user's coins to %s" % str(DECIMAL_ZERO), usage="") - bot.events.on("received.command.richest").hook( + events.on("received.command.richest").hook( self.richest, help="Show the top 10 richest users") - bot.events.on("received.command.redeemcoins").hook( + events.on("received.command.redeemcoins").hook( self.redeem_coins, help="Redeem free coins") - bot.events.on("received.command.flip").hook(self.flip, + events.on("received.command.flip").hook(self.flip, help="Bet coins on a coin flip", usage= "heads|tails ", min_args=2, protect_registered=True) - bot.events.on("received.command.sendcoins").hook( + events.on("received.command.sendcoins").hook( self.send, min_args=2, help="Send coins to a user", usage=" ", authenticated=True) - bot.events.on("received.command.roulette").hook( + events.on("received.command.roulette").hook( self.roulette, min_args=2, help="Spin the roulette wheel", usage=" ", protect_registered=True) @@ -53,7 +53,7 @@ class Module(object): until_next_hour = 60-now.second until_next_hour += ((60-(now.minute+1))*60) - bot.events.on("timer").on("coin-interest").hook(self.interest) + events.on("timer").on("coin-interest").hook(self.interest) bot.add_timer("coin-interest", INTEREST_INTERVAL, persist=False, next_due=time.time()+until_next_hour) diff --git a/modules/commands.py b/modules/commands.py index fbce393d..5084f690 100644 --- a/modules/commands.py +++ b/modules/commands.py @@ -45,27 +45,28 @@ class StdErr(Out): self.module_name, Utils.FONT_RESET) class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("message").on("channel").hook( + self.events = events + events.on("received").on("message").on("channel").hook( self.channel_message) - bot.events.on("received").on("message").on("private").hook( + events.on("received").on("message").on("private").hook( self.private_message) - bot.events.on("received").on("command").on("help").hook(self.help, + events.on("received").on("command").on("help").hook(self.help, help="Show help for commands", usage="") - bot.events.on("received").on("command").on("usage").hook(self.usage, + events.on("received").on("command").on("usage").hook(self.usage, help="Show usage help for commands", min_args=1, usage="") - bot.events.on("received").on("command").on("more").hook(self.more, + events.on("received").on("command").on("more").hook(self.more, help="Get more output from the last command", skip_out=True) - bot.events.on("postboot").on("configure").on( + events.on("postboot").on("configure").on( "channelset").assure_call(setting="command-prefix", help="Set the command prefix used in this channel") - bot.events.on("new").on("user", "channel").hook(self.new) - bot.events.on("send").on("stdout").hook(self.send_stdout) - bot.events.on("send").on("stderr").hook(self.send_stderr) + events.on("new").on("user", "channel").hook(self.new) + events.on("send").on("stdout").hook(self.send_stdout) + events.on("send").on("stderr").hook(self.send_stderr) def new(self, event): if "user" in event: @@ -76,10 +77,10 @@ class Module(object): target.last_stderr = None def has_command(self, command): - return command.lower() in self.bot.events.on("received").on( + return command.lower() in self.events.on("received").on( "command").get_children() def get_hook(self, command): - return self.bot.events.on("received").on("command").on(command + return self.events.on("received").on("command").on(command ).get_hooks()[0] def is_highlight(self, server, s): @@ -108,7 +109,7 @@ class Module(object): stdout, stderr = StdOut(module_name, target), StdErr(module_name, target) - returns = self.bot.events.on("preprocess").on("command" + returns = self.events.on("preprocess").on("command" ).call(hook=hook, user=event["user"], server=event["server"], target=target, is_channel=is_channel) for returned in returns: @@ -129,7 +130,7 @@ class Module(object): args = " ".join(args_split) server = event["server"] user = event["user"] - self.bot.events.on("received").on("command").on(command + self.events.on("received").on("command").on(command ).call_limited(1, user=user, server=server, target=target, buffer=buffer, args=args, args_split=args_split, stdout=stdout, stderr=stderr, @@ -162,9 +163,9 @@ class Module(object): def help(self, event): if event["args"]: command = event["args_split"][0].lower() - if command in self.bot.events.on("received").on( + if command in self.events.on("received").on( "command").get_children(): - hooks = self.bot.events.on("received").on("command").on(command).get_hooks() + hooks = self.events.on("received").on("command").on(command).get_hooks() if hooks and "help" in hooks[0].kwargs: event["stdout"].write("%s: %s" % (command, hooks[0].kwargs["help"])) else: @@ -173,8 +174,8 @@ class Module(object): event["stderr"].write("Unknown command '%s'" % command) else: help_available = [] - for child in self.bot.events.on("received").on("command").get_children(): - hooks = self.bot.events.on("received").on("command").on(child).get_hooks() + for child in self.events.on("received").on("command").get_children(): + hooks = self.events.on("received").on("command").on(child).get_hooks() if hooks and "help" in hooks[0].kwargs: help_available.append(child) help_available = sorted(help_available) @@ -182,9 +183,9 @@ class Module(object): def usage(self, event): command = event["args_split"][0].lower() - if command in self.bot.events.on("received").on( + if command in self.events.on("received").on( "command").get_children(): - hooks = self.bot.events.on("received").on("command").on(command).get_hooks() + hooks = self.events.on("received").on("command").on(command).get_hooks() if hooks and "usage" in hooks[0].kwargs: event["stdout"].write("Usage: %s %s" % (command, hooks[0].kwargs["usage"])) else: diff --git a/modules/ctcp.py b/modules/ctcp.py index 031b39cd..5320369a 100644 --- a/modules/ctcp.py +++ b/modules/ctcp.py @@ -1,10 +1,10 @@ import datetime class Module(object): - def __init__(self, bot): - bot.events.on("received").on("message").on("private").hook( - self.private_message) + def __init__(self, bot, events): self.bot = bot + events.on("received").on("message").on("private").hook( + self.private_message) def private_message(self, event): if event["message"][0] == "\x01" and event["message"][-1] == "\x01": diff --git a/modules/define.py b/modules/define.py index c5e62b6a..6f17164c 100644 --- a/modules/define.py +++ b/modules/define.py @@ -5,9 +5,9 @@ import Utils URL_WORDNIK = "http://api.wordnik.com:80/v4/word.json/%s/definitions" class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("command").on("define").hook( + events.on("received").on("command").on("define").hook( self.define, help="Define a provided term", usage="") diff --git a/modules/dns.py b/modules/dns.py index 2935e1bf..43499601 100644 --- a/modules/dns.py +++ b/modules/dns.py @@ -2,8 +2,8 @@ import socket class Module(object): _name = "DNS" - def __init__(self, bot): - bot.events.on("received").on("command").on("dns").hook( + def __init__(self, bot, events): + events.on("received").on("command").on("dns").hook( self.dns, min_args=1, help="Get all addresses for a given hostname (IPv4/IPv6)", usage="") diff --git a/modules/ducks.py b/modules/ducks.py index 685a49f9..d67c2608 100644 --- a/modules/ducks.py +++ b/modules/ducks.py @@ -7,23 +7,24 @@ DUCK_LAST_SEEN = datetime.datetime.now() class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.log = IRCLogging.Log self.bot = bot + self.events = events self.active_duck = 0 - bot.events.on("received.command.bef").hook(self.duck_bef, + events.on("received.command.bef").hook(self.duck_bef, help="Befriend a duck!") - bot.events.on("received.command.bang").hook(self.duck_bang, + events.on("received.command.bang").hook(self.duck_bang, help="Shoot a duck! Meanie.") - bot.events.on("received.command.decoy").hook(self.set_decoy, + events.on("received.command.decoy").hook(self.set_decoy, help="Be a sneaky fellow and make a decoy duck.") - # bot.events.on("received.command.friends").hook(self.duck_friends, + # events.on("received.command.friends").hook(self.duck_friends, # help="See who the friendliest people to ducks are!") - # bot.events.on("received.command.killers").hook(self.duck_killers, + # events.on("received.command.killers").hook(self.duck_killers, # help="See who shoots the most amount of ducks.") - # bot.events.on("received.command.ducks").hook(self.duck_list, + # events.on("received.command.ducks").hook(self.duck_list, # help="Shows a list of the most popular duck superstars.") now = datetime.datetime.now() @@ -35,22 +36,22 @@ class Module(object): tricky = next_duck_time - now.second tricky += ((next_duck_time - (now.minute + 1)) * 2) - bot.events.on("postboot").on("configure").on( + events.on("postboot").on("configure").on( "channelset").assure_call(setting="ducks-enabled", help="Toggles ducks! (1 or 0)") - bot.events.on("postboot").on("configure").on( + events.on("postboot").on("configure").on( "channelset").assure_call(setting="min-duck-time", help="Minimum seconds before a duck is summoned") - bot.events.on("postboot").on("configure").on( + events.on("postboot").on("configure").on( "channelset").assure_call(setting="max-duck-time", help="Max seconds before a duck is summoned") - bot.events.on("timer").on("duck-appear").hook(self.show_duck) + events.on("timer").on("duck-appear").hook(self.show_duck) bot.add_timer("duck-appear", next_duck_time, persist=False) - bot.events.on("received.numeric.366").hook(self.bootstrap) + events.on("received.numeric.366").hook(self.bootstrap) def bootstrap(self, event): for server in self.bot.servers.values(): @@ -198,7 +199,7 @@ class Module(object): def set_decoy(self, event): next_decoy_time = self.decoy_time() - self.bot.events.on("timer").on("duck-decoy").hook(self.duck_decoy) + self.events.on("timer").on("duck-decoy").hook(self.duck_decoy) self.bot.add_timer("duck-decoy", next_decoy_time, persist=False) # def coins(self, event): diff --git a/modules/geoip.py b/modules/geoip.py index 7615575c..bd874d76 100644 --- a/modules/geoip.py +++ b/modules/geoip.py @@ -4,8 +4,8 @@ URL_GEOIP = "http://ip-api.com/json/%s" class Module(object): _name = "GeoIP" - def __init__(self, bot): - bot.events.on("received").on("command").on("geoip").hook( + def __init__(self, bot, events): + events.on("received").on("command").on("geoip").hook( self.geoip, min_args=1, help="Get geoip data on a given IPv4/IPv6 address", usage="") diff --git a/modules/google.py b/modules/google.py index b8d5c653..632c5fd2 100644 --- a/modules/google.py +++ b/modules/google.py @@ -6,9 +6,9 @@ import Utils URL_GOOGLESEARCH = "https://www.googleapis.com/customsearch/v1" class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("command").on("google", + events.on("received").on("command").on("google", "g").hook(self.google, help="Google feeling lucky", usage="[search term]") diff --git a/modules/hash.py b/modules/hash.py index 86657bd1..19f0591f 100644 --- a/modules/hash.py +++ b/modules/hash.py @@ -1,9 +1,9 @@ import hashlib class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("command").on("hash" + events.on("received").on("command").on("hash" ).hook(self.hash, min_args=2, help="Hash a string", usage=" ") diff --git a/modules/haveibeenpwned.py b/modules/haveibeenpwned.py index fa10129c..854f69f3 100644 --- a/modules/haveibeenpwned.py +++ b/modules/haveibeenpwned.py @@ -4,8 +4,8 @@ URL_HAVEIBEENPWNEDAPI = "https://haveibeenpwned.com/api/v2/breachedaccount/%s" URL_HAVEIBEENPWNED = "https://haveibeenpwned.com/" class Module(object): - def __init__(self, bot): - bot.events.on("received").on("command").on("beenpwned").hook( + def __init__(self, bot, events): + events.on("received").on("command").on("beenpwned").hook( self.beenpwned, min_args=1, help="Find out if a username, email or similar has appeared " "in any hacked databases", usage="") diff --git a/modules/ids.py b/modules/ids.py index c8bd8042..0c8ba0bf 100644 --- a/modules/ids.py +++ b/modules/ids.py @@ -2,10 +2,10 @@ class Module(object): _name = "IDs" - def __init__(self, bot): - bot.events.on("received.command.myid").hook(self.my_id, + def __init__(self, bot, events): + events.on("received.command.myid").hook(self.my_id, help="Show your user ID") - bot.events.on("received.command.channelid").hook( + events.on("received.command.channelid").hook( self.channel_id, channel_only=True, help="Show the current channel's ID") diff --git a/modules/imdb.py b/modules/imdb.py index c24b4c0a..71458638 100644 --- a/modules/imdb.py +++ b/modules/imdb.py @@ -8,9 +8,9 @@ URL_IMDBTITLE = "http://imdb.com/title/%s" class Module(object): _name = "IMDb" - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("command").on("imdb").hook( + events.on("received").on("command").on("imdb").hook( self.imdb, min_args=1, help="Search for a given title on IMDb", usage="") diff --git a/modules/in.py b/modules/in.py index 4f4aef51..2ac6a9bc 100644 --- a/modules/in.py +++ b/modules/in.py @@ -5,12 +5,12 @@ SECONDS_MAX = Utils.SECONDS_WEEKS*8 SECONDS_MAX_DESCRIPTION = "8 weeks" class Module(object): - def __init__(self, bot): + def __init__(self, bot, events): self.bot = bot - bot.events.on("received").on("command").on("in").hook( + events.on("received").on("command").on("in").hook( self.in_command, min_args=2, help="Set a reminder", usage="