From da84c6685ec55a612cbe284edb4c5ad967097931 Mon Sep 17 00:00:00 2001 From: Joscha Date: Fri, 8 Sep 2017 11:16:44 +0000 Subject: [PATCH] Improve bot command parsing Further improvements: - add message.mid or session.uid or session.sid - use "messages" instead of "log" and "sessions" instead of "listing" where they're only lists --- yaboli/bot.py | 75 ++++++++++++++++++++++---------------------- yaboli/controller.py | 2 +- yaboli/utils.py | 24 ++++++++++++++ 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/yaboli/bot.py b/yaboli/bot.py index dfc192b..8e6d38c 100644 --- a/yaboli/bot.py +++ b/yaboli/bot.py @@ -1,4 +1,5 @@ import asyncio +from collections import namedtuple import logging import re import time @@ -16,6 +17,8 @@ class Bot(Controller): SPECIFIC_RE = r"!(\S+)\s+@(\S+)([\S\s]*)" GENERIC_RE = r"!(\S+)([\S\s]*)" + ParsedMessage = namedtuple("ParsedMessage", ["command", "argstr"]) + def __init__(self, nick): super().__init__(nick) @@ -60,50 +63,48 @@ class Bot(Controller): await self.stop() def noargs(func): - async def wrapper(self, message, args): - if not args: + async def wrapper(self, message, argstr): + if not argstr: return await func(self, message) return wrapper async def on_send(self, message): - parsed = self.parse_message(message.content) - if not parsed: - return - command, args = parsed + wait = [] - # general callback (specific set to False) - general = asyncio.ensure_future( - self._callbacks.call((command, False), message, args) - ) + specific = self.parse_message(message.content, specific=True) + if specific: + wait.append(self._callbacks.call( + (specific.command, True), + message, + specific.argstr + )) - if len(args) > 0: - name = args[0] - args = args[1:] - if name[:1] == "@" and similar(name[1:], self.nick): - logger.debug("Specific command!") - # specific callback (specific set to True) - await self._callbacks.call((command, True), message, args) + general = self.parse_message(message.content, specific=False) + if general: + wait.append(self._callbacks.call( + (general.command, False), + message, + general.argstr + )) - await general + if wait: + await asyncio.wait(wait) - def parse_message(self, content): + def parse_message(self, content, specific=True): """ - (command, args) = parse_message(content) + ParsedMessage = parse_message(content) Returns None, not a (None, None) tuple, when message could not be parsed """ - match = re.fullmatch(self.GENERIC_RE, content) - if not match: - return None - - command = match.group(1) - argstr = match.group(2) - args = self.parse_args(argstr) - - logger.debug(f"Parsed command. command={command!r}, args={args!r}") - - return command, args + if specific: + match = re.fullmatch(self.SPECIFIC_RE, content) + if match and similar(match.group(2), self.nick): + return self.ParsedMessage(match.group(1), match.group(3)) + else: + match = re.fullmatch(self.GENERIC_RE, content) + if match: + return self.ParsedMessage(match.group(1), match.group(2)) def parse_args(self, text): """ @@ -188,17 +189,17 @@ class Bot(Controller): @noargs async def command_ping(self, message): if self.ping_message: - await self.room.send(self.ping_message, message.message_id) + await self.room.send(self.ping_message, message.mid) @noargs # TODO: specific command help (!help @bot ping) async def command_help(self, message): if self.help_specific: - await self.room.send(self.help_specific, message.message_id) + await self.room.send(self.help_specific, message.mid) @noargs async def command_help_general(self, message): if self.help_general is not None: - await self.room.send(self.help_general, message.message_id) + await self.room.send(self.help_general, message.mid) @noargs async def command_uptime(self, message): @@ -206,13 +207,13 @@ class Bot(Controller): startformat = format_time(self.start_time) deltaformat = format_time_delta(now - self.start_time) text = f"/me has been up since {startformat} ({deltaformat})" - await self.room.send(text, message.message_id) + await self.room.send(text, message.mid) async def command_kill(self, message, args): logging.warn(f"Kill attempt by @{mention(message.sender.nick)} in &{self.room.roomname}: {message.content!r}") if self.kill_message is not None: - await self.room.send(self.kill_message, message.message_id) + await self.room.send(self.kill_message, message.mid) if self.killable: await self.stop() @@ -221,7 +222,7 @@ class Bot(Controller): logging.warn(f"Restart attempt by @{mention(message.sender.nick)} in &{self.room.roomname}: {message.content!r}") if self.restart_message is not None: - await self.room.send(self.restart_message, message.message_id) + await self.room.send(self.restart_message, message.mid) if self.restartable: await self.restart() diff --git a/yaboli/controller.py b/yaboli/controller.py index 5c84ff8..14faec3 100644 --- a/yaboli/controller.py +++ b/yaboli/controller.py @@ -207,7 +207,7 @@ class Controller: async def on_send(self, message): pass - async def on_snapshot(self, user_id, session_id, version, listing, log, nick=None, + async def on_snapshot(self, user_id, session_id, version, sessions, messages, nick=None, pm_with_nick=None, pm_with_user_id=None): if nick != self.nick: await self.room.nick(self.nick) diff --git a/yaboli/utils.py b/yaboli/utils.py index 716b797..760ca0b 100644 --- a/yaboli/utils.py +++ b/yaboli/utils.py @@ -108,6 +108,22 @@ class Session: self.client_address = client_address self.real_address = real_address + @property + def uid(self): + return self.user_id + + @uid.setter + def uid(self, new_uid): + self.user_id = new_uid + + @property + def sid(self): + return self.session_id + + @sid.setter + def sid(self, new_sid): + self.session_id = new_sid + @classmethod def from_dict(cls, d): return cls( @@ -188,6 +204,14 @@ class Message(): self.deleted = deleted self.truncated = truncated + @property + def mid(self): + return self.message_id + + @mid.setter + def mid(self, new_mid): + self.message_id = new_mid + @classmethod def from_dict(cls, d): return cls(