mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-07-16 02:50:48 +00:00
✨ Feature: 优化事件分发方法 (#2067)
This commit is contained in:
@ -80,7 +80,10 @@ RUN_POSTPCS_PARAMS = (
|
||||
|
||||
|
||||
def event_preprocessor(func: T_EventPreProcessor) -> T_EventPreProcessor:
|
||||
"""事件预处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之前执行。"""
|
||||
"""事件预处理。
|
||||
|
||||
装饰一个函数,使它在每次接收到事件并分发给各响应器之前执行。
|
||||
"""
|
||||
_event_preprocessors.add(
|
||||
Dependent[Any].parse(call=func, allow_types=EVENT_PCS_PARAMS)
|
||||
)
|
||||
@ -88,7 +91,10 @@ def event_preprocessor(func: T_EventPreProcessor) -> T_EventPreProcessor:
|
||||
|
||||
|
||||
def event_postprocessor(func: T_EventPostProcessor) -> T_EventPostProcessor:
|
||||
"""事件后处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之后执行。"""
|
||||
"""事件后处理。
|
||||
|
||||
装饰一个函数,使它在每次接收到事件并分发给各响应器之后执行。
|
||||
"""
|
||||
_event_postprocessors.add(
|
||||
Dependent[Any].parse(call=func, allow_types=EVENT_PCS_PARAMS)
|
||||
)
|
||||
@ -96,7 +102,10 @@ def event_postprocessor(func: T_EventPostProcessor) -> T_EventPostProcessor:
|
||||
|
||||
|
||||
def run_preprocessor(func: T_RunPreProcessor) -> T_RunPreProcessor:
|
||||
"""运行预处理。装饰一个函数,使它在每次事件响应器运行前执行。"""
|
||||
"""运行预处理。
|
||||
|
||||
装饰一个函数,使它在每次事件响应器运行前执行。
|
||||
"""
|
||||
_run_preprocessors.add(
|
||||
Dependent[Any].parse(call=func, allow_types=RUN_PREPCS_PARAMS)
|
||||
)
|
||||
@ -104,13 +113,222 @@ def run_preprocessor(func: T_RunPreProcessor) -> T_RunPreProcessor:
|
||||
|
||||
|
||||
def run_postprocessor(func: T_RunPostProcessor) -> T_RunPostProcessor:
|
||||
"""运行后处理。装饰一个函数,使它在每次事件响应器运行后执行。"""
|
||||
"""运行后处理。
|
||||
|
||||
装饰一个函数,使它在每次事件响应器运行后执行。
|
||||
"""
|
||||
_run_postprocessors.add(
|
||||
Dependent[Any].parse(call=func, allow_types=RUN_POSTPCS_PARAMS)
|
||||
)
|
||||
return func
|
||||
|
||||
|
||||
async def _apply_event_preprocessors(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
show_log: bool = True,
|
||||
) -> bool:
|
||||
"""运行事件预处理。
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
event: Event 对象
|
||||
state: 会话状态
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
show_log: 是否显示日志
|
||||
|
||||
返回:
|
||||
是否继续处理事件
|
||||
"""
|
||||
if not _event_preprocessors:
|
||||
return True
|
||||
|
||||
if show_log:
|
||||
logger.debug("Running PreProcessors...")
|
||||
|
||||
try:
|
||||
await asyncio.gather(
|
||||
*(
|
||||
run_coro_with_catch(
|
||||
proc(
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
),
|
||||
(SkippedException,),
|
||||
)
|
||||
for proc in _event_preprocessors
|
||||
)
|
||||
)
|
||||
except IgnoredException as e:
|
||||
logger.opt(colors=True).info(
|
||||
f"Event {escape_tag(event.get_event_name())} is <b>ignored</b>"
|
||||
)
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).error(
|
||||
"<r><bg #f8bbd0>Error when running EventPreProcessors. "
|
||||
"Event ignored!</bg #f8bbd0></r>"
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def _apply_event_postprocessors(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
show_log: bool = True,
|
||||
) -> None:
|
||||
"""运行事件后处理。
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
event: Event 对象
|
||||
state: 会话状态
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
show_log: 是否显示日志
|
||||
"""
|
||||
if not _event_postprocessors:
|
||||
return
|
||||
|
||||
if show_log:
|
||||
logger.debug("Running PostProcessors...")
|
||||
|
||||
try:
|
||||
await asyncio.gather(
|
||||
*(
|
||||
run_coro_with_catch(
|
||||
proc(
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
),
|
||||
(SkippedException,),
|
||||
)
|
||||
for proc in _event_postprocessors
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).error(
|
||||
"<r><bg #f8bbd0>Error when running EventPostProcessors</bg #f8bbd0></r>"
|
||||
)
|
||||
|
||||
|
||||
async def _apply_run_preprocessors(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
matcher: Matcher,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> bool:
|
||||
"""运行事件响应器运行前处理。
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
event: Event 对象
|
||||
state: 会话状态
|
||||
matcher: 事件响应器
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
|
||||
返回:
|
||||
是否继续处理事件
|
||||
"""
|
||||
if not _run_preprocessors:
|
||||
return True
|
||||
|
||||
# ensure matcher function can be correctly called
|
||||
with matcher.ensure_context(bot, event):
|
||||
try:
|
||||
await asyncio.gather(
|
||||
*(
|
||||
run_coro_with_catch(
|
||||
proc(
|
||||
matcher=matcher,
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
),
|
||||
(SkippedException,),
|
||||
)
|
||||
for proc in _run_preprocessors
|
||||
)
|
||||
)
|
||||
except IgnoredException:
|
||||
logger.opt(colors=True).info(f"{matcher} running is <b>cancelled</b>")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).error(
|
||||
"<r><bg #f8bbd0>Error when running RunPreProcessors. "
|
||||
"Running cancelled!</bg #f8bbd0></r>"
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def _apply_run_postprocessors(
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
matcher: Matcher,
|
||||
exception: Optional[Exception] = None,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> None:
|
||||
"""运行事件响应器运行后处理。
|
||||
|
||||
Args:
|
||||
bot: Bot 对象
|
||||
event: Event 对象
|
||||
matcher: 事件响应器
|
||||
exception: 事件响应器运行异常
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
"""
|
||||
if not _run_postprocessors:
|
||||
return
|
||||
|
||||
with matcher.ensure_context(bot, event):
|
||||
try:
|
||||
await asyncio.gather(
|
||||
*(
|
||||
run_coro_with_catch(
|
||||
proc(
|
||||
matcher=matcher,
|
||||
exception=exception,
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=matcher.state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
),
|
||||
(SkippedException,),
|
||||
)
|
||||
for proc in _run_postprocessors
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).error(
|
||||
"<r><bg #f8bbd0>Error when running RunPostProcessors</bg #f8bbd0></r>"
|
||||
)
|
||||
|
||||
|
||||
async def _check_matcher(
|
||||
Matcher: Type[Matcher],
|
||||
bot: "Bot",
|
||||
@ -118,27 +336,39 @@ async def _check_matcher(
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> None:
|
||||
) -> bool:
|
||||
"""检查事件响应器是否符合运行条件。
|
||||
|
||||
请注意,过时的事件响应器将被**销毁**。对于未过时的事件响应器,将会一次检查其响应类型、权限和规则。
|
||||
|
||||
参数:
|
||||
Matcher: 要检查的事件响应器
|
||||
bot: Bot 对象
|
||||
event: Event 对象
|
||||
state: 会话状态
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
|
||||
返回:
|
||||
bool: 是否符合运行条件
|
||||
"""
|
||||
if Matcher.expire_time and datetime.now() > Matcher.expire_time:
|
||||
with contextlib.suppress(Exception):
|
||||
Matcher.destroy()
|
||||
return
|
||||
return False
|
||||
|
||||
try:
|
||||
if not await Matcher.check_perm(
|
||||
bot, event, stack, dependency_cache
|
||||
) or not await Matcher.check_rule(bot, event, state, stack, dependency_cache):
|
||||
return
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).error(
|
||||
f"<r><bg #f8bbd0>Rule check failed for {Matcher}.</bg #f8bbd0></r>"
|
||||
)
|
||||
return
|
||||
return False
|
||||
|
||||
if Matcher.temp:
|
||||
with contextlib.suppress(Exception):
|
||||
Matcher.destroy()
|
||||
await _run_matcher(Matcher, bot, event, state, stack, dependency_cache)
|
||||
return True
|
||||
|
||||
|
||||
async def _run_matcher(
|
||||
@ -149,36 +379,38 @@ async def _run_matcher(
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> None:
|
||||
"""运行事件响应器。
|
||||
|
||||
临时事件响应器将在运行前被**销毁**。
|
||||
|
||||
参数:
|
||||
Matcher: 事件响应器
|
||||
bot: Bot 对象
|
||||
event: Event 对象
|
||||
state: 会话状态
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
|
||||
异常:
|
||||
StopPropagation: 阻止事件继续传播
|
||||
"""
|
||||
logger.info(f"Event will be handled by {Matcher}")
|
||||
|
||||
matcher = Matcher()
|
||||
if coros := [
|
||||
run_coro_with_catch(
|
||||
proc(
|
||||
matcher=matcher,
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
),
|
||||
(SkippedException,),
|
||||
)
|
||||
for proc in _run_preprocessors
|
||||
]:
|
||||
# ensure matcher function can be correctly called
|
||||
with matcher.ensure_context(bot, event):
|
||||
try:
|
||||
await asyncio.gather(*coros)
|
||||
except IgnoredException:
|
||||
logger.opt(colors=True).info(f"{matcher} running is <b>cancelled</b>")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).error(
|
||||
"<r><bg #f8bbd0>Error when running RunPreProcessors. Running cancelled!</bg #f8bbd0></r>"
|
||||
)
|
||||
if Matcher.temp:
|
||||
with contextlib.suppress(Exception):
|
||||
Matcher.destroy()
|
||||
|
||||
return
|
||||
matcher = Matcher()
|
||||
|
||||
if not await _apply_run_preprocessors(
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
matcher=matcher,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
):
|
||||
return
|
||||
|
||||
exception = None
|
||||
|
||||
@ -191,33 +423,55 @@ async def _run_matcher(
|
||||
)
|
||||
exception = e
|
||||
|
||||
if coros := [
|
||||
run_coro_with_catch(
|
||||
proc(
|
||||
matcher=matcher,
|
||||
exception=exception,
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=matcher.state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
),
|
||||
(SkippedException,),
|
||||
)
|
||||
for proc in _run_postprocessors
|
||||
]:
|
||||
# ensure matcher function can be correctly called
|
||||
with matcher.ensure_context(bot, event):
|
||||
try:
|
||||
await asyncio.gather(*coros)
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).error(
|
||||
"<r><bg #f8bbd0>Error when running RunPostProcessors</bg #f8bbd0></r>"
|
||||
)
|
||||
await _apply_run_postprocessors(
|
||||
bot=bot,
|
||||
event=event,
|
||||
matcher=matcher,
|
||||
exception=exception,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
)
|
||||
|
||||
if matcher.block:
|
||||
raise StopPropagation
|
||||
return
|
||||
|
||||
|
||||
async def check_and_run_matcher(
|
||||
Matcher: Type[Matcher],
|
||||
bot: "Bot",
|
||||
event: "Event",
|
||||
state: T_State,
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> None:
|
||||
"""检查并运行事件响应器。
|
||||
|
||||
参数:
|
||||
Matcher: 事件响应器
|
||||
bot: Bot 对象
|
||||
event: Event 对象
|
||||
state: 会话状态
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
"""
|
||||
if not await _check_matcher(
|
||||
Matcher=Matcher,
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
):
|
||||
return
|
||||
|
||||
await _run_matcher(
|
||||
Matcher=Matcher,
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
)
|
||||
|
||||
|
||||
async def handle_event(bot: "Bot", event: "Event") -> None:
|
||||
@ -245,35 +499,16 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
|
||||
state: Dict[Any, Any] = {}
|
||||
dependency_cache: T_DependencyCache = {}
|
||||
|
||||
# create event scope context
|
||||
async with AsyncExitStack() as stack:
|
||||
if coros := [
|
||||
run_coro_with_catch(
|
||||
proc(
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
),
|
||||
(SkippedException,),
|
||||
)
|
||||
for proc in _event_preprocessors
|
||||
]:
|
||||
try:
|
||||
if show_log:
|
||||
logger.debug("Running PreProcessors...")
|
||||
await asyncio.gather(*coros)
|
||||
except IgnoredException as e:
|
||||
logger.opt(colors=True).info(
|
||||
f"Event {escape_tag(event.get_event_name())} is <b>ignored</b>"
|
||||
)
|
||||
return
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).error(
|
||||
"<r><bg #f8bbd0>Error when running EventPreProcessors. "
|
||||
"Event ignored!</bg #f8bbd0></r>"
|
||||
)
|
||||
return
|
||||
if not await _apply_event_preprocessors(
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
):
|
||||
return
|
||||
|
||||
# Trie Match
|
||||
try:
|
||||
@ -284,6 +519,7 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
|
||||
)
|
||||
|
||||
break_flag = False
|
||||
# iterate through all priority until stop propagation
|
||||
for priority in sorted(matchers.keys()):
|
||||
if break_flag:
|
||||
break
|
||||
@ -292,14 +528,12 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
|
||||
logger.debug(f"Checking for matchers in priority {priority}...")
|
||||
|
||||
pending_tasks = [
|
||||
_check_matcher(
|
||||
check_and_run_matcher(
|
||||
matcher, bot, event, state.copy(), stack, dependency_cache
|
||||
)
|
||||
for matcher in matchers[priority]
|
||||
]
|
||||
|
||||
results = await asyncio.gather(*pending_tasks, return_exceptions=True)
|
||||
|
||||
for result in results:
|
||||
if not isinstance(result, Exception):
|
||||
continue
|
||||
@ -314,24 +548,4 @@ async def handle_event(bot: "Bot", event: "Event") -> None:
|
||||
if show_log:
|
||||
logger.debug("Checking for matchers completed")
|
||||
|
||||
if coros := [
|
||||
run_coro_with_catch(
|
||||
proc(
|
||||
bot=bot,
|
||||
event=event,
|
||||
state=state,
|
||||
stack=stack,
|
||||
dependency_cache=dependency_cache,
|
||||
),
|
||||
(SkippedException,),
|
||||
)
|
||||
for proc in _event_postprocessors
|
||||
]:
|
||||
try:
|
||||
if show_log:
|
||||
logger.debug("Running PostProcessors...")
|
||||
await asyncio.gather(*coros)
|
||||
except Exception as e:
|
||||
logger.opt(colors=True, exception=e).error(
|
||||
"<r><bg #f8bbd0>Error when running EventPostProcessors</bg #f8bbd0></r>"
|
||||
)
|
||||
await _apply_event_postprocessors(bot, event, state, stack, dependency_cache)
|
||||
|
Reference in New Issue
Block a user