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
This commit is contained in:
parent
5b0f078f7a
commit
da84c6685e
3 changed files with 63 additions and 38 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from collections import namedtuple
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
@ -16,6 +17,8 @@ class Bot(Controller):
|
||||||
SPECIFIC_RE = r"!(\S+)\s+@(\S+)([\S\s]*)"
|
SPECIFIC_RE = r"!(\S+)\s+@(\S+)([\S\s]*)"
|
||||||
GENERIC_RE = r"!(\S+)([\S\s]*)"
|
GENERIC_RE = r"!(\S+)([\S\s]*)"
|
||||||
|
|
||||||
|
ParsedMessage = namedtuple("ParsedMessage", ["command", "argstr"])
|
||||||
|
|
||||||
def __init__(self, nick):
|
def __init__(self, nick):
|
||||||
super().__init__(nick)
|
super().__init__(nick)
|
||||||
|
|
||||||
|
|
@ -60,50 +63,48 @@ class Bot(Controller):
|
||||||
await self.stop()
|
await self.stop()
|
||||||
|
|
||||||
def noargs(func):
|
def noargs(func):
|
||||||
async def wrapper(self, message, args):
|
async def wrapper(self, message, argstr):
|
||||||
if not args:
|
if not argstr:
|
||||||
return await func(self, message)
|
return await func(self, message)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
async def on_send(self, message):
|
async def on_send(self, message):
|
||||||
parsed = self.parse_message(message.content)
|
wait = []
|
||||||
if not parsed:
|
|
||||||
return
|
|
||||||
command, args = parsed
|
|
||||||
|
|
||||||
# general callback (specific set to False)
|
specific = self.parse_message(message.content, specific=True)
|
||||||
general = asyncio.ensure_future(
|
if specific:
|
||||||
self._callbacks.call((command, False), message, args)
|
wait.append(self._callbacks.call(
|
||||||
)
|
(specific.command, True),
|
||||||
|
message,
|
||||||
|
specific.argstr
|
||||||
|
))
|
||||||
|
|
||||||
if len(args) > 0:
|
general = self.parse_message(message.content, specific=False)
|
||||||
name = args[0]
|
if general:
|
||||||
args = args[1:]
|
wait.append(self._callbacks.call(
|
||||||
if name[:1] == "@" and similar(name[1:], self.nick):
|
(general.command, False),
|
||||||
logger.debug("Specific command!")
|
message,
|
||||||
# specific callback (specific set to True)
|
general.argstr
|
||||||
await self._callbacks.call((command, True), message, args)
|
))
|
||||||
|
|
||||||
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
|
Returns None, not a (None, None) tuple, when message could not be parsed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
match = re.fullmatch(self.GENERIC_RE, content)
|
if specific:
|
||||||
if not match:
|
match = re.fullmatch(self.SPECIFIC_RE, content)
|
||||||
return None
|
if match and similar(match.group(2), self.nick):
|
||||||
|
return self.ParsedMessage(match.group(1), match.group(3))
|
||||||
command = match.group(1)
|
else:
|
||||||
argstr = match.group(2)
|
match = re.fullmatch(self.GENERIC_RE, content)
|
||||||
args = self.parse_args(argstr)
|
if match:
|
||||||
|
return self.ParsedMessage(match.group(1), match.group(2))
|
||||||
logger.debug(f"Parsed command. command={command!r}, args={args!r}")
|
|
||||||
|
|
||||||
return command, args
|
|
||||||
|
|
||||||
def parse_args(self, text):
|
def parse_args(self, text):
|
||||||
"""
|
"""
|
||||||
|
|
@ -188,17 +189,17 @@ class Bot(Controller):
|
||||||
@noargs
|
@noargs
|
||||||
async def command_ping(self, message):
|
async def command_ping(self, message):
|
||||||
if self.ping_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)
|
@noargs # TODO: specific command help (!help @bot ping)
|
||||||
async def command_help(self, message):
|
async def command_help(self, message):
|
||||||
if self.help_specific:
|
if self.help_specific:
|
||||||
await self.room.send(self.help_specific, message.message_id)
|
await self.room.send(self.help_specific, message.mid)
|
||||||
|
|
||||||
@noargs
|
@noargs
|
||||||
async def command_help_general(self, message):
|
async def command_help_general(self, message):
|
||||||
if self.help_general is not None:
|
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
|
@noargs
|
||||||
async def command_uptime(self, message):
|
async def command_uptime(self, message):
|
||||||
|
|
@ -206,13 +207,13 @@ class Bot(Controller):
|
||||||
startformat = format_time(self.start_time)
|
startformat = format_time(self.start_time)
|
||||||
deltaformat = format_time_delta(now - self.start_time)
|
deltaformat = format_time_delta(now - self.start_time)
|
||||||
text = f"/me has been up since {startformat} ({deltaformat})"
|
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):
|
async def command_kill(self, message, args):
|
||||||
logging.warn(f"Kill attempt by @{mention(message.sender.nick)} in &{self.room.roomname}: {message.content!r}")
|
logging.warn(f"Kill attempt by @{mention(message.sender.nick)} in &{self.room.roomname}: {message.content!r}")
|
||||||
|
|
||||||
if self.kill_message is not None:
|
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:
|
if self.killable:
|
||||||
await self.stop()
|
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}")
|
logging.warn(f"Restart attempt by @{mention(message.sender.nick)} in &{self.room.roomname}: {message.content!r}")
|
||||||
|
|
||||||
if self.restart_message is not None:
|
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:
|
if self.restartable:
|
||||||
await self.restart()
|
await self.restart()
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,7 @@ class Controller:
|
||||||
async def on_send(self, message):
|
async def on_send(self, message):
|
||||||
pass
|
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):
|
pm_with_nick=None, pm_with_user_id=None):
|
||||||
if nick != self.nick:
|
if nick != self.nick:
|
||||||
await self.room.nick(self.nick)
|
await self.room.nick(self.nick)
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,22 @@ class Session:
|
||||||
self.client_address = client_address
|
self.client_address = client_address
|
||||||
self.real_address = real_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
|
@classmethod
|
||||||
def from_dict(cls, d):
|
def from_dict(cls, d):
|
||||||
return cls(
|
return cls(
|
||||||
|
|
@ -188,6 +204,14 @@ class Message():
|
||||||
self.deleted = deleted
|
self.deleted = deleted
|
||||||
self.truncated = truncated
|
self.truncated = truncated
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mid(self):
|
||||||
|
return self.message_id
|
||||||
|
|
||||||
|
@mid.setter
|
||||||
|
def mid(self, new_mid):
|
||||||
|
self.message_id = new_mid
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, d):
|
def from_dict(cls, d):
|
||||||
return cls(
|
return cls(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue