mirror of
https://github.com/nonebot/nonebot2.git
synced 2024-12-18 09:25:46 +08:00
Add CommandSession.switch()
This commit is contained in:
parent
fa32ad6425
commit
de9a4e5b83
@ -170,7 +170,7 @@ class _FurtherInteractionNeeded(Exception):
|
||||
class _FinishException(Exception):
|
||||
"""
|
||||
Raised by session.finish() indicating that the command session
|
||||
should be stop and removed.
|
||||
should be stopped and removed.
|
||||
"""
|
||||
|
||||
def __init__(self, result: bool = True):
|
||||
@ -180,6 +180,24 @@ class _FinishException(Exception):
|
||||
self.result = result
|
||||
|
||||
|
||||
class SwitchException(Exception):
|
||||
"""
|
||||
Raised by session.switch() indicating that the command session
|
||||
should be stopped and replaced with a new one (going through
|
||||
handle_message() again).
|
||||
|
||||
Since the new context message will go through handle_message()
|
||||
again, the later function should be notified. So this exception
|
||||
is designed to be propagated to handle_message().
|
||||
"""
|
||||
|
||||
def __init__(self, new_ctx_message: Message):
|
||||
"""
|
||||
:param new_ctx_message: new message which should be placed in context
|
||||
"""
|
||||
self.new_ctx_message = new_ctx_message
|
||||
|
||||
|
||||
class CommandSession(BaseSession):
|
||||
__slots__ = ('cmd', 'current_key', 'current_arg', 'current_arg_text',
|
||||
'current_arg_images', 'args', '_last_interaction', '_running')
|
||||
@ -278,6 +296,26 @@ class CommandSession(BaseSession):
|
||||
asyncio.ensure_future(self.send(message))
|
||||
raise _FinishException
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
def switch(self, new_ctx_message: Any) -> None:
|
||||
"""
|
||||
Finish the session and switch to a new (fake) message context.
|
||||
|
||||
The user may send another command (or another intention as natural
|
||||
language) when interacting with the current session. In this case,
|
||||
the session may not understand what the user is saying, so it
|
||||
should call this method and pass in that message, then NoneBot will
|
||||
handle the situation properly.
|
||||
"""
|
||||
if self.is_first_run:
|
||||
# if calling this method during first run,
|
||||
# we think the command is not handled
|
||||
raise _FinishException(result=False)
|
||||
|
||||
if not isinstance(new_ctx_message, Message):
|
||||
new_ctx_message = Message(new_ctx_message)
|
||||
raise SwitchException(new_ctx_message)
|
||||
|
||||
|
||||
def parse_command(bot: NoneBot,
|
||||
cmd_string: str) -> Tuple[Optional[Command], Optional[str]]:
|
||||
@ -433,9 +471,11 @@ async def _real_run_command(session: CommandSession,
|
||||
ctx_id: str,
|
||||
disable_interaction: bool = False,
|
||||
**kwargs) -> bool:
|
||||
session_overridden = False
|
||||
if not disable_interaction:
|
||||
# override session only when not disabling interaction
|
||||
_sessions[ctx_id] = session
|
||||
session_overridden = True
|
||||
try:
|
||||
logger.debug(f'Running command {session.cmd.name}')
|
||||
session.running = True
|
||||
@ -450,10 +490,20 @@ async def _real_run_command(session: CommandSession,
|
||||
f'command {session.cmd.name}')
|
||||
# return True because this step of the session is successful
|
||||
return True
|
||||
except _FinishException as e:
|
||||
except (_FinishException, SwitchException) as e:
|
||||
session.running = False
|
||||
logger.debug(f'Session of command {session.cmd.name} finished')
|
||||
if not disable_interaction and ctx_id in _sessions:
|
||||
if session_overridden:
|
||||
# the command is finished, remove the session
|
||||
del _sessions[ctx_id]
|
||||
return e.result
|
||||
|
||||
if isinstance(e, _FinishException):
|
||||
return e.result
|
||||
elif isinstance(e, SwitchException):
|
||||
# we are guaranteed that the session is not first run here
|
||||
if ctx_id in _sessions:
|
||||
# make sure there is no session waiting
|
||||
del _sessions[ctx_id]
|
||||
logger.debug(f'Session of command {session.cmd.name} switching,'
|
||||
f'new context message: {e.new_ctx_message}')
|
||||
raise e # this is intended to be propagated to handle_message()
|
||||
|
@ -3,7 +3,7 @@ from typing import Dict, Any
|
||||
from aiocqhttp.message import MessageSegment
|
||||
|
||||
from . import NoneBot
|
||||
from .command import handle_command
|
||||
from .command import handle_command, SwitchException
|
||||
from .log import logger
|
||||
from .natural_language import handle_natural_language
|
||||
|
||||
@ -23,7 +23,14 @@ async def handle_message(bot: NoneBot, ctx: Dict[str, Any]) -> None:
|
||||
else:
|
||||
ctx['to_me'] = True
|
||||
|
||||
handled = await handle_command(bot, ctx)
|
||||
while True:
|
||||
try:
|
||||
handled = await handle_command(bot, ctx)
|
||||
break
|
||||
except SwitchException as e:
|
||||
# we are sure that there is no session existing now
|
||||
ctx['message'] = e.new_ctx_message
|
||||
ctx['to_me'] = True
|
||||
if handled:
|
||||
logger.info(f'Message {ctx["message_id"]} is handled as a command')
|
||||
return
|
||||
|
Loading…
Reference in New Issue
Block a user