🎨 change temp matcher process #50

This commit is contained in:
yanyongyu 2020-11-16 11:25:42 +08:00
parent b5ea66359c
commit 6986232290
3 changed files with 62 additions and 54 deletions

View File

@ -9,12 +9,6 @@
from nonebot.typing import List, Type, Optional from nonebot.typing import List, Type, Optional
class _ExceptionContainer(Exception):
def __init__(self, exceptions: List[Type[Exception]]) -> None:
self.exceptions = exceptions
class IgnoredException(Exception): class IgnoredException(Exception):
""" """
:说明: :说明:

View File

@ -9,10 +9,9 @@ from datetime import datetime
from nonebot.log import logger from nonebot.log import logger
from nonebot.rule import TrieRule from nonebot.rule import TrieRule
from nonebot.utils import escape_tag from nonebot.utils import escape_tag
from nonebot.matcher import matchers from nonebot.matcher import matchers, Matcher
from nonebot.exception import IgnoredException, ExpiredException from nonebot.typing import Set, Type, Union, Iterable, NoReturn, Bot, Event
from nonebot.exception import StopPropagation, _ExceptionContainer from nonebot.exception import IgnoredException, ExpiredException, StopPropagation
from nonebot.typing import Set, Type, Union, NoReturn, Bot, Event, Matcher
from nonebot.typing import EventPreProcessor, RunPreProcessor, EventPostProcessor, RunPostProcessor from nonebot.typing import EventPreProcessor, RunPreProcessor, EventPostProcessor, RunPostProcessor
_event_preprocessors: Set[EventPreProcessor] = set() _event_preprocessors: Set[EventPreProcessor] = set()
@ -41,20 +40,46 @@ def run_postprocessor(func: RunPostProcessor) -> RunPostProcessor:
return func return func
async def _check_matcher(priority: int, bot: Bot, event: Event,
state: dict) -> Iterable[Type[Matcher]]:
current_matchers = matchers[priority].copy()
async def _check(Matcher: Type[Matcher], bot: Bot, event: Event,
state: dict) -> Optional[Type[Matcher]]:
try:
if await Matcher.check_perm(
bot, event) and await Matcher.check_rule(bot, event, state):
return Matcher
except Exception as e:
logger.opt(colors=True, exception=e).error(
f"<r><bg #f8bbd0>Rule check failed for {Matcher}.</bg #f8bbd0></r>"
)
return None
async def _check_expire(Matcher: Type[Matcher]) -> Optional[Type[Matcher]]:
if Matcher.temp or (Matcher.expire_time and
datetime.now() > Matcher.expire_time):
return Matcher
return None
checking_tasks = [
_check(Matcher, bot, event, state) for Matcher in current_matchers
]
checking_expire_tasks = [
_check_expire(Matcher) for Matcher in current_matchers
]
results = await asyncio.gather(*checking_tasks, return_exceptions=True)
expired = await asyncio.gather(*checking_expire_tasks)
for expired_matcher in filter(lambda x: issubclass(Matcher), expired):
try:
matchers[priority].remove(expired_matcher)
except Exception:
pass
return filter(lambda x: issubclass(Matcher), results)
async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event, async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event,
state: dict) -> Union[None, NoReturn]: state: dict) -> Union[None, NoReturn]:
if Matcher.expire_time and datetime.now() > Matcher.expire_time:
raise _ExceptionContainer([ExpiredException])
try:
if not await Matcher.check_perm(
bot, event) or not await Matcher.check_rule(bot, event, state):
return
except Exception as e:
logger.opt(colors=True, exception=e).error(
f"<r><bg #f8bbd0>Rule check failed for {Matcher}.</bg #f8bbd0></r>")
return
logger.info(f"Event will be handled by {Matcher}") logger.info(f"Event will be handled by {Matcher}")
matcher = Matcher() matcher = Matcher()
@ -74,7 +99,7 @@ async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event,
"Running cancelled!</bg #f8bbd0></r>") "Running cancelled!</bg #f8bbd0></r>")
return return
exceptions = [] exception = None
try: try:
logger.debug(f"Running matcher {matcher}") logger.debug(f"Running matcher {matcher}")
@ -83,15 +108,10 @@ async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event,
logger.opt(colors=True, exception=e).error( logger.opt(colors=True, exception=e).error(
f"<r><bg #f8bbd0>Running matcher {matcher} failed.</bg #f8bbd0></r>" f"<r><bg #f8bbd0>Running matcher {matcher} failed.</bg #f8bbd0></r>"
) )
exceptions.append(e) exception = e
if Matcher.temp:
exceptions.append(ExpiredException)
if Matcher.block:
exceptions.append(StopPropagation)
coros = list( coros = list(
map(lambda x: x(matcher, exceptions, bot, event, state), map(lambda x: x(matcher, exception, bot, event, state),
_run_postprocessors)) _run_postprocessors))
if coros: if coros:
try: try:
@ -101,8 +121,8 @@ async def _run_matcher(Matcher: Type[Matcher], bot: Bot, event: Event,
"<r><bg #f8bbd0>Error when running RunPostProcessors</bg #f8bbd0></r>" "<r><bg #f8bbd0>Error when running RunPostProcessors</bg #f8bbd0></r>"
) )
if exceptions: if matcher.block:
raise _ExceptionContainer(exceptions) raise StopPropagation
async def handle_event(bot: Bot, event: Event): async def handle_event(bot: Bot, event: Event):
@ -153,29 +173,23 @@ async def handle_event(bot: Bot, event: Event):
if break_flag: if break_flag:
break break
pending_tasks = [
_run_matcher(matcher, bot, event, state.copy())
for matcher in matchers[priority]
]
if show_log: if show_log:
logger.debug(f"Checking for matchers in priority {priority}...") logger.debug(f"Checking for matchers in priority {priority}...")
run_matchers = _check_matcher(priority, bot, event, state)
pending_tasks = [
_run_matcher(matcher, bot, event, state.copy())
for matcher in run_matchers
]
results = await asyncio.gather(*pending_tasks, return_exceptions=True) results = await asyncio.gather(*pending_tasks, return_exceptions=True)
i = 0 for result in results:
for index, result in enumerate(results): if result is StopPropagation:
if isinstance(result, _ExceptionContainer): if not break_flag:
e_list = result.exceptions break_flag = True
if StopPropagation in e_list: logger.debug("Stop event propagation")
if not break_flag:
break_flag = True
logger.debug("Stop event propagation")
if ExpiredException in e_list:
logger.debug(
f"Matcher {matchers[priority][index - i]} will be removed."
)
del matchers[priority][index - i]
i += 1
coros = list(map(lambda x: x(bot, event, state), _event_postprocessors)) coros = list(map(lambda x: x(bot, event, state), _event_postprocessors))
if coros: if coros:

View File

@ -119,14 +119,14 @@ RunPreProcessor = Callable[["Matcher", Bot, Event, dict],
事件响应器运行前预处理函数 RunPreProcessor 类型 事件响应器运行前预处理函数 RunPreProcessor 类型
""" """
RunPostProcessor = Callable[["Matcher", List[Any], Bot, Event, dict], RunPostProcessor = Callable[["Matcher", Optional[Exception], Bot, Event, dict],
Union[Awaitable[None], Awaitable[NoReturn]]] Union[Awaitable[None], Awaitable[NoReturn]]]
""" """
:类型: ``Callable[[Matcher, List[Any], Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]`` :类型: ``Callable[[Matcher, Optional[Exception], Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]``
:说明: :说明:
事件响应器运行前预处理函数 RunPostProcessor 类型第二个参数包含运行时产生的错误以及 ``ExpiredException``, ``StopPropagation`` (如果存在) 事件响应器运行前预处理函数 RunPostProcessor 类型第二个参数为运行时产生的错误如果存在
""" """
Matcher = TypeVar("Matcher", bound="MatcherClass") Matcher = TypeVar("Matcher", bound="MatcherClass")