Skip to content

Commit 4eba5e0

Browse files
authored
Merge pull request CloudBotIRC#178 from linuxdaemon/gonzobot+outgoing-sieves
Add outgoing raw line hooks
2 parents 2bc8551 + 207a9f0 commit 4eba5e0

8 files changed

Lines changed: 581 additions & 46 deletions

File tree

cloudbot/clients/irc.py

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ssl import SSLContext
77

88
from cloudbot.client import Client
9-
from cloudbot.event import Event, EventType
9+
from cloudbot.event import Event, EventType, IrcOutEvent
1010
from cloudbot.util import async_util
1111

1212
logger = logging.getLogger("cloudbot")
@@ -21,8 +21,10 @@
2121
irc_bad_chars = ''.join([chr(x) for x in list(range(0, 1)) + list(range(4, 32)) + list(range(127, 160))])
2222
irc_clean_re = re.compile('[{}]'.format(re.escape(irc_bad_chars)))
2323

24+
2425
def irc_clean(dirty):
25-
return irc_clean_re.sub('',dirty)
26+
return irc_clean_re.sub('', dirty)
27+
2628

2729
irc_command_to_event_type = {
2830
"PRIVMSG": EventType.message,
@@ -292,9 +294,39 @@ def send(self, line):
292294
# make sure we are connected before sending
293295
if not self._connected:
294296
yield from self._connected_future
295-
line = line[:510] + "\r\n"
296-
data = line.encode("utf-8", "replace")
297-
self._transport.write(data)
297+
298+
old_line = line
299+
filtered = bool(self.bot.plugin_manager.out_sieves)
300+
301+
for out_sieve in self.bot.plugin_manager.out_sieves:
302+
event = IrcOutEvent(
303+
bot=self.bot, hook=out_sieve, conn=self.conn, irc_raw=line
304+
)
305+
306+
ok, new_line = yield from self.bot.plugin_manager.internal_launch(out_sieve, event)
307+
if not ok:
308+
logger.warning("Error occurred in outgoing sieve, falling back to old behavior")
309+
logger.debug("Line was: %s", line)
310+
filtered = False
311+
break
312+
313+
line = new_line
314+
if line is not None and not isinstance(line, bytes):
315+
line = str(line)
316+
317+
if not line:
318+
return
319+
320+
if not filtered:
321+
# No outgoing sieves loaded or one of the sieves errored, fall back to old behavior
322+
line = old_line[:510] + "\r\n"
323+
line = line.encode("utf-8", "replace")
324+
325+
if not isinstance(line, bytes):
326+
# the line must be encoded before we send it, one of the sieves didn't encode it, fall back to the default
327+
line = line.encode("utf-8", "replace")
328+
329+
self._transport.write(line)
298330

299331
def data_received(self, data):
300332
self._input_buffer += data
@@ -412,12 +444,3 @@ def data_received(self, data):
412444

413445
# handle the message, async
414446
async_util.wrap_future(self.bot.process(event), loop=self.loop)
415-
416-
# Channel Commands
417-
# NOTICE #chan :Text
418-
# PRIVMSG #chan :Text
419-
# KICK #chan nick :reason
420-
# JOIN #chan
421-
# PART #chan :reason
422-
# MODE #chan +<modes>
423-
# INVITE nick :#chan

cloudbot/event.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import sys
99

10+
from cloudbot.util.parsers.irc import Message
11+
1012
logger = logging.getLogger("cloudbot")
1113

1214

@@ -419,3 +421,43 @@ def __init__(self, *args, cap, cap_param=None, **kwargs):
419421
super().__init__(*args, **kwargs)
420422
self.cap = cap
421423
self.cap_param = cap_param
424+
425+
426+
class IrcOutEvent(Event):
427+
def __init__(self, *args, **kwargs):
428+
super().__init__(*args, **kwargs)
429+
self.parsed_line = None
430+
431+
@asyncio.coroutine
432+
def prepare(self):
433+
yield from super().prepare()
434+
435+
if "parsed_line" in self.hook.required_args:
436+
try:
437+
self.parsed_line = Message.parse(self.line)
438+
except Exception:
439+
logger.exception("Unable to parse line requested by hook %s", self.hook)
440+
self.parsed_line = None
441+
442+
def prepare_threaded(self):
443+
super().prepare_threaded()
444+
445+
if "parsed_line" in self.hook.required_args:
446+
try:
447+
self.parsed_line = Message.parse(self.line)
448+
except Exception:
449+
logger.exception("Unable to parse line requested by hook %s", self.hook)
450+
self.parsed_line = None
451+
452+
@property
453+
def line(self):
454+
return str(self.irc_raw)
455+
456+
457+
class PostHookEvent(Event):
458+
def __init__(self, *args, launched_hook=None, launched_event=None, result=None, error=None, **kwargs):
459+
super().__init__(*args, **kwargs)
460+
self.launched_hook = launched_hook
461+
self.launched_event = launched_event
462+
self.result = result
463+
self.error = error

cloudbot/hook.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import collections
22
import inspect
33
import re
4-
import collections
54
from enum import Enum, unique, IntEnum
65

76
from cloudbot.event import EventType
@@ -384,18 +383,21 @@ def on_stop(param=None, **kwargs):
384383
"""External on_stop decorator. Can be used directly as a decorator, or with args to return a decorator
385384
:type param: function | None
386385
"""
386+
387387
def _on_stop_hook(func):
388388
hook = _get_hook(func, "on_stop")
389389
if hook is None:
390390
hook = _Hook(func, "on_stop")
391391
_add_hook(func, hook)
392392
hook._add_hook(kwargs)
393393
return func
394+
394395
if callable(param):
395396
return _on_stop_hook(param)
396397
else:
397398
return lambda func: _on_stop_hook(func)
398399

400+
399401
on_unload = on_stop
400402

401403

@@ -451,6 +453,42 @@ def _on_connect_hook(func):
451453
connect = on_connect
452454

453455

456+
def irc_out(param=None, **kwargs):
457+
def _decorate(func):
458+
hook = _get_hook(func, "irc_out")
459+
if hook is None:
460+
hook = _Hook(func, "irc_out")
461+
_add_hook(func, hook)
462+
463+
hook._add_hook(kwargs)
464+
return func
465+
466+
if callable(param):
467+
return _decorate(param)
468+
else:
469+
return lambda func: _decorate(func)
470+
471+
472+
def post_hook(param=None, **kwargs):
473+
"""
474+
This hook will be fired just after a hook finishes executing
475+
"""
476+
477+
def _decorate(func):
478+
hook = _get_hook(func, "post_hook")
479+
if hook is None:
480+
hook = _Hook(func, "post_hook")
481+
_add_hook(func, hook)
482+
483+
hook._add_hook(kwargs)
484+
return func
485+
486+
if callable(param):
487+
return _decorate(param)
488+
else:
489+
return lambda func: _decorate(func)
490+
491+
454492
def permission(*perms, **kwargs):
455493
def _perm_hook(func):
456494
assert len(inspect.getfullargspec(func).args) == 3, \

0 commit comments

Comments
 (0)