Skip to content

Commit e9bdee4

Browse files
committed
fix merge conflict
2 parents d6d65a4 + 940e70e commit e9bdee4

5 files changed

Lines changed: 93 additions & 25 deletions

File tree

cloudbot/bot.py

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55
import re
66
import os
77
import gc
8+
from operator import attrgetter
9+
810
from sqlalchemy import create_engine
911

1012
from sqlalchemy.orm import scoped_session, sessionmaker
1113
from sqlalchemy.ext.declarative import declarative_base
1214
from sqlalchemy.schema import MetaData
1315

14-
import cloudbot
1516
from cloudbot.client import Client
1617
from cloudbot.config import Config
18+
from cloudbot.hook import Action
1719
from cloudbot.reloader import PluginReloader
1820
from cloudbot.plugin import PluginManager
1921
from cloudbot.event import Event, CommandEvent, RegexEvent, EventType
@@ -221,23 +223,46 @@ def process(self, event):
221223
run_before_tasks = []
222224
tasks = []
223225
command_prefix = event.conn.config.get('command_prefix', '.')
226+
halted = False
227+
228+
def add_hook(hook, _event, _run_before=False):
229+
nonlocal halted
230+
if halted:
231+
return False
232+
233+
coro = self.plugin_manager.launch(hook, _event)
234+
if _run_before:
235+
run_before_tasks.append(coro)
236+
else:
237+
tasks.append(coro)
238+
239+
if hook.action is Action.HALTALL:
240+
halted = True
241+
return False
242+
elif hook.action is Action.HALTTYPE:
243+
return False
244+
return True
224245

225246
# Raw IRC hook
226247
for raw_hook in self.plugin_manager.catch_all_triggers:
227248
# run catch-all coroutine hooks before all others - TODO: Make this a plugin argument
228-
if not raw_hook.threaded:
229-
run_before_tasks.append(
230-
self.plugin_manager.launch(raw_hook, Event(hook=raw_hook, base_event=event)))
231-
else:
232-
tasks.append(self.plugin_manager.launch(raw_hook, Event(hook=raw_hook, base_event=event)))
249+
run_before = not raw_hook.threaded
250+
if not add_hook(raw_hook, Event(hook=raw_hook, base_event=event), _run_before=run_before):
251+
# The hook has an action of Action.HALT* so stop adding new tasks
252+
break
253+
233254
if event.irc_command in self.plugin_manager.raw_triggers:
234255
for raw_hook in self.plugin_manager.raw_triggers[event.irc_command]:
235-
tasks.append(self.plugin_manager.launch(raw_hook, Event(hook=raw_hook, base_event=event)))
256+
if not add_hook(raw_hook, Event(hook=raw_hook, base_event=event)):
257+
# The hook has an action of Action.HALT* so stop adding new tasks
258+
break
236259

237260
# Event hooks
238261
if event.type in self.plugin_manager.event_type_hooks:
239262
for event_hook in self.plugin_manager.event_type_hooks[event.type]:
240-
tasks.append(self.plugin_manager.launch(event_hook, Event(hook=event_hook, base_event=event)))
263+
if not add_hook(event_hook, Event(hook=event_hook, base_event=event)):
264+
# The hook has an action of Action.HALT* so stop adding new tasks
265+
break
241266

242267
if event.type is EventType.message:
243268
# Commands
@@ -258,7 +283,7 @@ def process(self, event):
258283
command_hook = self.plugin_manager.commands[command]
259284
command_event = CommandEvent(hook=command_hook, text=text,
260285
triggered_command=command, base_event=event)
261-
tasks.append(self.plugin_manager.launch(command_hook, command_event))
286+
add_hook(command_hook, command_event)
262287
else:
263288
potential_matches = []
264289
for potential_match, plugin in self.plugin_manager.commands.items():
@@ -269,20 +294,27 @@ def process(self, event):
269294
command_hook = potential_matches[0][1]
270295
command_event = CommandEvent(hook=command_hook, text=text,
271296
triggered_command=command, base_event=event)
272-
tasks.append(self.plugin_manager.launch(command_hook, command_event))
297+
add_hook(command_hook, command_event)
273298
else:
274299
event.notice("Possible matches: {}".format(
275300
formatting.get_text_list([command for command, plugin in potential_matches])))
276301

277302
# Regex hooks
303+
regex_matched = False
278304
for regex, regex_hook in self.plugin_manager.regex_hooks:
279305
if not regex_hook.run_on_cmd and cmd_match:
280-
pass
281-
else:
282-
regex_match = regex.search(event.content)
283-
if regex_match:
284-
regex_event = RegexEvent(hook=regex_hook, match=regex_match, base_event=event)
285-
tasks.append(self.plugin_manager.launch(regex_hook, regex_event))
306+
continue
307+
308+
if regex_hook.only_no_match and regex_matched:
309+
continue
310+
311+
regex_match = regex.search(event.content)
312+
if regex_match:
313+
regex_matched = True
314+
regex_event = RegexEvent(hook=regex_hook, match=regex_match, base_event=event)
315+
if not add_hook(regex_hook, regex_event):
316+
# The hook has an action of Action.HALT* so stop adding new tasks
317+
break
286318

287319
# Run the tasks
288320
yield from asyncio.gather(*run_before_tasks, loop=self.loop)

cloudbot/hook.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
11
import collections
22
import inspect
33
import re
4+
import collections
5+
from enum import Enum, unique, IntEnum
46

57
from cloudbot.event import EventType
68

79
valid_command_re = re.compile(r"^\w+$")
810

911

12+
@unique
13+
class Priority(IntEnum):
14+
# Reversed to maintain compatibility with sieve hooks numeric priority
15+
LOWEST = 127
16+
LOW = 63
17+
NORMAL = 0
18+
HIGH = -64
19+
HIGHEST = -128
20+
21+
22+
@unique
23+
class Action(Enum):
24+
"""Defines the action to take after executing a hook"""
25+
HALTTYPE = 0 # Once this hook executes, no other hook of that type should run
26+
HALTALL = 1 # Once this hook executes, No other hook should run
27+
CONTINUE = 2 # Normal execution of all hooks
28+
29+
1030
class _Hook:
1131
"""
1232
:type function: function

cloudbot/plugin.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
import re
88
from collections import defaultdict
99
from operator import attrgetter
10+
from itertools import chain
1011

1112
import sqlalchemy
1213

1314
from cloudbot.event import Event
15+
from cloudbot.hook import Priority, Action
1416
from cloudbot.util import database
1517

1618
logger = logging.getLogger("cloudbot")
@@ -254,6 +256,15 @@ def load_plugin(self, path):
254256
self.sieves.sort(key=lambda x: x.priority)
255257
self.connect_hooks.sort(key=attrgetter("priority"))
256258

259+
# Sort hooks
260+
self.regex_hooks.sort(key=lambda x: x[1].priority)
261+
dicts_of_lists_of_hooks = (self.event_type_hooks, self.raw_triggers)
262+
lists_of_hooks = [self.catch_all_triggers, self.sieves]
263+
lists_of_hooks.extend(chain.from_iterable(d.values() for d in dicts_of_lists_of_hooks))
264+
265+
for lst in lists_of_hooks:
266+
lst.sort(key=lambda x: x.priority)
267+
257268
# we don't need this anymore
258269
del plugin.run_on_start
259270

@@ -643,6 +654,8 @@ def __init__(self, _type, plugin, func_hook):
643654

644655
self.permissions = func_hook.kwargs.pop("permissions", [])
645656
self.single_thread = func_hook.kwargs.pop("singlethread", False)
657+
self.action = func_hook.kwargs.pop("action", Action.CONTINUE)
658+
self.priority = func_hook.kwargs.pop("priority", Priority.NORMAL)
646659

647660
if func_hook.kwargs:
648661
# we should have popped all the args, so warn if there are any left
@@ -699,6 +712,7 @@ def __init__(self, plugin, regex_hook):
699712
:type regex_hook: cloudbot.util.hook._RegexHook
700713
"""
701714
self.run_on_cmd = regex_hook.kwargs.pop("run_on_cmd", False)
715+
self.only_no_match = regex_hook.kwargs.pop("only_no_match", False)
702716

703717
self.regexes = regex_hook.regexes
704718

plugins/duckhunt.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,10 +296,10 @@ def befriend(nick, chan, message, db, conn, notice):
296296
return "There is no hunt right now. Use .starthunt to start a game."
297297
elif game_status[network][chan]['duck_status'] != 1:
298298
if game_status[network][chan]['no_duck_kick'] == 1:
299-
out = "KICK {} {} :You tried befriending a non-existent duck, that's fucking creepy.".format(chan, nick)
299+
out = "KICK {} {} :You tried befriending a non-existent duck. That's fucking creepy.".format(chan, nick)
300300
conn.send(out)
301301
return
302-
return "You tried befriending a non-existent duck, that's fucking creepy."
302+
return "You tried befriending a non-existent duck. That's fucking creepy."
303303
else:
304304
game_status[network][chan]['shoot_time'] = time()
305305
deploy = game_status[network][chan]['duck_time']

plugins/link_announcer.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@
44
from contextlib import closing
55
from cloudbot import hook
66

7-
# This will match any URL except the patterns defined in blacklist.
8-
blacklist = '.*(reddit\.com|redd\.it|youtube\.com|youtu\.be|imdb\.com|spotify\.com|twitter\.com|twitch\.tv|amazon\.co|xkcd\.com|amzn\.co|steamcommunity\.com|steampowered\.com|newegg\.com|soundcloud\.com|vimeo\.com|speedtest\.net).*'
9-
url_re = re.compile('(?!{})http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+~]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+'.format(blacklist), re.I)
7+
from cloudbot.hook import Priority, Action
8+
9+
# This will match any URL, blacklist removed and abstracted to a priority/halting system
10+
url_re = re.compile(r'https?://(?:[a-zA-Z]|[0-9]|[$-_@.&+~]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', re.I)
1011

1112
opt_out = []
1213

1314
traditional = [
1415
(1024 ** 5, 'PB'),
15-
(1024 ** 4, 'TB'),
16-
(1024 ** 3, 'GB'),
17-
(1024 ** 2, 'MB'),
16+
(1024 ** 4, 'TB'),
17+
(1024 ** 3, 'GB'),
18+
(1024 ** 2, 'MB'),
1819
(1024 ** 1, 'KB'),
1920
(1024 ** 0, 'B'),
2021
]
@@ -29,7 +30,8 @@ def bytesto(bytes, system = traditional):
2930
amount = int(bytes/factor)
3031
return str(amount) + suffix
3132

32-
@hook.regex(url_re)
33+
34+
@hook.regex(url_re, priority=Priority.LOW, action=Action.HALTTYPE, only_no_match=True)
3335
def print_url_title(message, match, chan):
3436
if chan in opt_out:
3537
return

0 commit comments

Comments
 (0)