[commands] Split process_commands into lower level bits.
This commit is contained in:
parent
87dc2f4dd3
commit
ce9d5b4f4a
@ -164,17 +164,6 @@ class BotBase(GroupMixin):
|
|||||||
|
|
||||||
# internal helpers
|
# internal helpers
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def _get_prefix(self, message):
|
|
||||||
prefix = self.command_prefix
|
|
||||||
if callable(prefix):
|
|
||||||
ret = prefix(self, message)
|
|
||||||
if asyncio.iscoroutine(ret):
|
|
||||||
ret = yield from ret
|
|
||||||
return ret
|
|
||||||
else:
|
|
||||||
return prefix
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def _run_extra(self, coro, event_name, *args, **kwargs):
|
def _run_extra(self, coro, event_name, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
@ -551,6 +540,105 @@ class BotBase(GroupMixin):
|
|||||||
|
|
||||||
# command processing
|
# command processing
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def get_prefix(self, message):
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Retrieves the prefix the bot is listening to
|
||||||
|
with the message as a context.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
message: :class:`discord.Message`
|
||||||
|
The message context to get the prefix of.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
Union[List[str], str]
|
||||||
|
A list of prefixes or a single prefix that the bot is
|
||||||
|
listening for.
|
||||||
|
"""
|
||||||
|
prefix = self.command_prefix
|
||||||
|
if callable(prefix):
|
||||||
|
ret = prefix(self, message)
|
||||||
|
if asyncio.iscoroutine(ret):
|
||||||
|
ret = yield from ret
|
||||||
|
return ret
|
||||||
|
else:
|
||||||
|
return prefix
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def get_context(self, message):
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Returns the invocation context from the message.
|
||||||
|
|
||||||
|
This is a more low-level counter-part for :meth:`process_message`
|
||||||
|
to allow users more fine grained control over the processing.
|
||||||
|
|
||||||
|
The returned context is not guaranteed to be a valid invocation
|
||||||
|
context, :attr:`Context.valid` must be checked to make sure it is.
|
||||||
|
If the context is not valid then it is not a valid candidate to be
|
||||||
|
invoked under :meth:`invoke`.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
message: :class:`discord.Message`
|
||||||
|
The message to get the invocation context from.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
--------
|
||||||
|
:class:`Context`
|
||||||
|
The invocation context.
|
||||||
|
"""
|
||||||
|
|
||||||
|
view = StringView(message.content)
|
||||||
|
ctx = Context(prefix=None, view=view, bot=self, message=message)
|
||||||
|
|
||||||
|
if self._skip_check(message.author.id, self.user.id):
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
prefix = yield from self.get_prefix(message)
|
||||||
|
invoked_prefix = prefix
|
||||||
|
|
||||||
|
if not isinstance(prefix, (tuple, list)):
|
||||||
|
if not view.skip_string(prefix):
|
||||||
|
return ctx
|
||||||
|
else:
|
||||||
|
invoked_prefix = discord.utils.find(view.skip_string, prefix)
|
||||||
|
if invoked_prefix is None:
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
invoker = view.get_word()
|
||||||
|
ctx.invoked_with = invoker
|
||||||
|
ctx.prefix = invoked_prefix
|
||||||
|
ctx.command = self.commands.get(invoker)
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def invoke(self, ctx):
|
||||||
|
"""|coro|
|
||||||
|
|
||||||
|
Invokes the command given under the invocation context and
|
||||||
|
handles all the internal event dispatch mechanisms.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
-----------
|
||||||
|
ctx: :class:`Context`
|
||||||
|
The invocation context to invoke.
|
||||||
|
"""
|
||||||
|
if ctx.command is not None:
|
||||||
|
self.dispatch('command', ctx)
|
||||||
|
try:
|
||||||
|
yield from ctx.command.invoke(ctx)
|
||||||
|
except CommandError as e:
|
||||||
|
ctx.command.dispatch_error(e, ctx)
|
||||||
|
else:
|
||||||
|
self.dispatch('command_completion', ctx)
|
||||||
|
elif ctx.invoked_with:
|
||||||
|
exc = CommandNotFound('Command "{}" is not found'.format(ctx.invoked_with))
|
||||||
|
self.dispatch('command_error', exc, ctx)
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def process_commands(self, message):
|
def process_commands(self, message):
|
||||||
"""|coro|
|
"""|coro|
|
||||||
@ -563,60 +651,16 @@ class BotBase(GroupMixin):
|
|||||||
event. If you choose to override the :func:`on_message` event, then
|
event. If you choose to override the :func:`on_message` event, then
|
||||||
you should invoke this coroutine as well.
|
you should invoke this coroutine as well.
|
||||||
|
|
||||||
Warning
|
This is built using other low level tools, and is equivalent to a
|
||||||
--------
|
call to :meth:`get_context` followed by a call to :meth:`invoke`.
|
||||||
This function is necessary for :meth:`say`, :meth:`whisper`,
|
|
||||||
:meth:`type`, :meth:`reply`, and :meth:`upload` to work due to the
|
|
||||||
way they are written. It is also required for the :func:`on_command`
|
|
||||||
and :func:`on_command_completion` events.
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
-----------
|
-----------
|
||||||
message : discord.Message
|
message : discord.Message
|
||||||
The message to process commands for.
|
The message to process commands for.
|
||||||
"""
|
"""
|
||||||
_internal_channel = message.channel
|
ctx = yield from self.get_context(message)
|
||||||
_internal_author = message.author
|
yield from self.invoke(ctx)
|
||||||
|
|
||||||
view = StringView(message.content)
|
|
||||||
if self._skip_check(message.author.id, self.user.id):
|
|
||||||
return
|
|
||||||
|
|
||||||
prefix = yield from self._get_prefix(message)
|
|
||||||
invoked_prefix = prefix
|
|
||||||
|
|
||||||
if not isinstance(prefix, (tuple, list)):
|
|
||||||
if not view.skip_string(prefix):
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
invoked_prefix = discord.utils.find(view.skip_string, prefix)
|
|
||||||
if invoked_prefix is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
invoker = view.get_word()
|
|
||||||
tmp = {
|
|
||||||
'bot': self,
|
|
||||||
'invoked_with': invoker,
|
|
||||||
'message': message,
|
|
||||||
'view': view,
|
|
||||||
'prefix': invoked_prefix
|
|
||||||
}
|
|
||||||
ctx = Context(**tmp)
|
|
||||||
del tmp
|
|
||||||
|
|
||||||
if invoker in self.commands:
|
|
||||||
command = self.commands[invoker]
|
|
||||||
self.dispatch('command', command, ctx)
|
|
||||||
try:
|
|
||||||
yield from command.invoke(ctx)
|
|
||||||
except CommandError as e:
|
|
||||||
ctx.command.dispatch_error(e, ctx)
|
|
||||||
else:
|
|
||||||
self.dispatch('command_completion', command, ctx)
|
|
||||||
elif invoker:
|
|
||||||
exc = CommandNotFound('Command "{}" is not found'.format(invoker))
|
|
||||||
self.dispatch('command_error', exc, ctx)
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def on_message(self, message):
|
def on_message(self, message):
|
||||||
|
@ -117,6 +117,11 @@ class Context(discord.abc.Messageable):
|
|||||||
ret = yield from command.callback(*arguments, **kwargs)
|
ret = yield from command.callback(*arguments, **kwargs)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@property
|
||||||
|
def valid(self):
|
||||||
|
"""Checks if the invocation context is valid to be invoked with."""
|
||||||
|
return self.prefix is not None and self.command is not None
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def _get_channel(self):
|
def _get_channel(self):
|
||||||
return self.channel
|
return self.channel
|
||||||
|
Loading…
x
Reference in New Issue
Block a user