2022-01-18 23:46:10 +08:00
""" 本模块定义了事件处理主要流程。
2020-11-16 15:06:37 +08:00
NoneBot 内部处理并按优先级分发事件给所有事件响应器 , 提供了多个插槽以进行事件的预处理等 。
2022-01-16 11:30:09 +08:00
FrontMatter :
sidebar_position : 2
description : nonebot . message 模块
2020-11-13 17:15:45 +08:00
"""
2020-07-25 12:28:30 +08:00
import asyncio
2022-08-14 19:41:00 +08:00
import contextlib
2020-08-06 17:54:55 +08:00
from datetime import datetime
2021-11-15 21:44:24 +08:00
from contextlib import AsyncExitStack
2022-09-08 10:37:16 +08:00
from typing import TYPE_CHECKING , Any , Set , Dict , Type , Optional
2020-07-25 12:28:30 +08:00
2020-07-05 20:39:34 +08:00
from nonebot . log import logger
2020-08-17 16:09:41 +08:00
from nonebot . rule import TrieRule
2021-12-12 18:19:08 +08:00
from nonebot . dependencies import Dependent
2021-11-16 18:30:16 +08:00
from nonebot . matcher import Matcher , matchers
2022-04-04 10:35:14 +08:00
from nonebot . utils import escape_tag , run_coro_with_catch
2021-12-06 00:17:52 +08:00
from nonebot . exception import (
NoLogException ,
StopPropagation ,
IgnoredException ,
SkippedException ,
)
2021-11-22 23:21:26 +08:00
from nonebot . typing import (
T_State ,
2021-12-16 23:22:25 +08:00
T_DependencyCache ,
2021-11-22 23:21:26 +08:00
T_RunPreProcessor ,
T_RunPostProcessor ,
T_EventPreProcessor ,
T_EventPostProcessor ,
)
2022-02-06 14:52:50 +08:00
from nonebot . internal . params import (
ArgParam ,
BotParam ,
EventParam ,
StateParam ,
DependParam ,
DefaultParam ,
MatcherParam ,
ExceptionParam ,
)
2020-12-06 02:30:19 +08:00
if TYPE_CHECKING :
2020-12-07 00:06:09 +08:00
from nonebot . adapters import Bot , Event
2020-07-25 12:28:30 +08:00
2022-02-04 11:06:38 +08:00
_event_preprocessors : Set [ Dependent [ Any ] ] = set ( )
_event_postprocessors : Set [ Dependent [ Any ] ] = set ( )
_run_preprocessors : Set [ Dependent [ Any ] ] = set ( )
_run_postprocessors : Set [ Dependent [ Any ] ] = set ( )
2021-11-16 18:30:16 +08:00
2022-09-09 11:52:57 +08:00
EVENT_PCS_PARAMS = (
2022-02-06 14:52:50 +08:00
DependParam ,
BotParam ,
EventParam ,
StateParam ,
DefaultParam ,
2022-09-09 11:52:57 +08:00
)
RUN_PREPCS_PARAMS = (
2022-02-06 14:52:50 +08:00
DependParam ,
BotParam ,
EventParam ,
StateParam ,
ArgParam ,
MatcherParam ,
DefaultParam ,
2022-09-09 11:52:57 +08:00
)
RUN_POSTPCS_PARAMS = (
2022-02-06 14:52:50 +08:00
DependParam ,
ExceptionParam ,
BotParam ,
EventParam ,
StateParam ,
ArgParam ,
MatcherParam ,
DefaultParam ,
2022-09-09 11:52:57 +08:00
)
2020-07-25 12:28:30 +08:00
2020-12-17 21:09:30 +08:00
def event_preprocessor ( func : T_EventPreProcessor ) - > T_EventPreProcessor :
2022-01-18 23:46:10 +08:00
""" 事件预处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之前执行。 """
2021-12-12 18:19:08 +08:00
_event_preprocessors . add (
2022-02-04 11:12:17 +08:00
Dependent [ Any ] . parse ( call = func , allow_types = EVENT_PCS_PARAMS )
2021-12-12 18:19:08 +08:00
)
2020-07-25 12:28:30 +08:00
return func
2020-07-04 22:51:10 +08:00
2020-12-17 21:09:30 +08:00
def event_postprocessor ( func : T_EventPostProcessor ) - > T_EventPostProcessor :
2022-01-18 23:46:10 +08:00
""" 事件后处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之后执行。 """
2021-12-12 18:19:08 +08:00
_event_postprocessors . add (
2022-02-04 11:12:17 +08:00
Dependent [ Any ] . parse ( call = func , allow_types = EVENT_PCS_PARAMS )
2021-12-12 18:19:08 +08:00
)
2020-11-07 17:35:44 +08:00
return func
2020-12-17 21:09:30 +08:00
def run_preprocessor ( func : T_RunPreProcessor ) - > T_RunPreProcessor :
2022-01-18 23:46:10 +08:00
""" 运行预处理。装饰一个函数,使它在每次事件响应器运行前执行。 """
2021-12-12 18:19:08 +08:00
_run_preprocessors . add (
2022-02-04 11:12:17 +08:00
Dependent [ Any ] . parse ( call = func , allow_types = RUN_PREPCS_PARAMS )
2021-12-12 18:19:08 +08:00
)
2020-11-07 17:35:44 +08:00
return func
2020-12-17 21:09:30 +08:00
def run_postprocessor ( func : T_RunPostProcessor ) - > T_RunPostProcessor :
2022-01-18 23:46:10 +08:00
""" 运行后处理。装饰一个函数,使它在每次事件响应器运行后执行。 """
2021-12-12 18:19:08 +08:00
_run_postprocessors . add (
2022-02-04 11:12:17 +08:00
Dependent [ Any ] . parse ( call = func , allow_types = RUN_POSTPCS_PARAMS )
2021-12-12 18:19:08 +08:00
)
2020-11-07 17:35:44 +08:00
return func
2021-11-21 12:36:44 +08:00
async def _check_matcher (
2021-11-22 23:21:26 +08:00
priority : int ,
Matcher : Type [ Matcher ] ,
bot : " Bot " ,
event : " Event " ,
state : T_State ,
stack : Optional [ AsyncExitStack ] = None ,
2021-12-16 23:22:25 +08:00
dependency_cache : Optional [ T_DependencyCache ] = None ,
2021-11-22 23:21:26 +08:00
) - > None :
2021-02-01 11:42:05 +08:00
if Matcher . expire_time and datetime . now ( ) > Matcher . expire_time :
2022-08-14 19:41:00 +08:00
with contextlib . suppress ( Exception ) :
2021-02-01 11:42:05 +08:00
matchers [ priority ] . remove ( Matcher )
return
try :
if not await Matcher . check_perm (
2021-11-22 23:21:26 +08:00
bot , event , stack , dependency_cache
) or not await Matcher . check_rule ( bot , event , state , stack , dependency_cache ) :
2021-02-01 11:42:05 +08:00
return
except Exception as e :
logger . opt ( colors = True , exception = e ) . error (
2021-11-22 23:21:26 +08:00
f " <r><bg #f8bbd0>Rule check failed for { Matcher } .</bg #f8bbd0></r> "
)
2021-02-03 11:23:13 +08:00
return
2021-02-01 11:42:05 +08:00
if Matcher . temp :
2022-08-14 19:41:00 +08:00
with contextlib . suppress ( Exception ) :
2021-02-01 11:42:05 +08:00
matchers [ priority ] . remove ( Matcher )
2021-11-21 12:36:44 +08:00
await _run_matcher ( Matcher , bot , event , state , stack , dependency_cache )
2020-08-21 14:24:32 +08:00
2020-11-16 11:25:42 +08:00
2021-11-21 12:36:44 +08:00
async def _run_matcher (
2021-11-22 23:21:26 +08:00
Matcher : Type [ Matcher ] ,
bot : " Bot " ,
event : " Event " ,
state : T_State ,
stack : Optional [ AsyncExitStack ] = None ,
2021-12-16 23:22:25 +08:00
dependency_cache : Optional [ T_DependencyCache ] = None ,
2021-11-22 23:21:26 +08:00
) - > None :
2020-08-26 17:47:36 +08:00
logger . info ( f " Event will be handled by { Matcher } " )
2020-08-21 14:24:32 +08:00
matcher = Matcher ( )
2022-08-14 19:41:00 +08:00
if coros := [
run_coro_with_catch (
proc (
matcher = matcher ,
bot = bot ,
event = event ,
state = state ,
stack = stack ,
dependency_cache = dependency_cache ,
2021-11-22 23:21:26 +08:00
) ,
2022-08-14 19:41:00 +08:00
( SkippedException , ) ,
2021-11-22 23:21:26 +08:00
)
2022-08-14 19:41:00 +08:00
for proc in _run_preprocessors
] :
2020-11-07 17:35:44 +08:00
try :
await asyncio . gather ( * coros )
except IgnoredException :
2022-09-09 11:52:57 +08:00
logger . opt ( colors = True ) . info ( f " { matcher } running is <b>cancelled</b> " )
2020-11-07 17:35:44 +08:00
return
except Exception as e :
logger . opt ( colors = True , exception = e ) . error (
2022-08-14 19:41:00 +08:00
" <r><bg #f8bbd0>Error when running RunPreProcessors. Running cancelled!</bg #f8bbd0></r> "
2021-11-22 23:21:26 +08:00
)
2022-08-14 19:41:00 +08:00
2020-11-07 17:35:44 +08:00
return
2020-11-16 11:25:42 +08:00
exception = None
2020-11-07 17:35:44 +08:00
2020-08-21 14:24:32 +08:00
try :
2022-09-09 11:52:57 +08:00
logger . debug ( f " Running { matcher } " )
2021-11-21 15:46:48 +08:00
await matcher . run ( bot , event , state , stack , dependency_cache )
2020-08-21 14:24:32 +08:00
except Exception as e :
2020-08-27 16:43:58 +08:00
logger . opt ( colors = True , exception = e ) . error (
2022-09-09 11:52:57 +08:00
f " <r><bg #f8bbd0>Running { matcher } failed.</bg #f8bbd0></r> "
2020-08-27 16:43:58 +08:00
)
2020-11-16 11:25:42 +08:00
exception = e
2020-11-07 17:35:44 +08:00
2022-08-14 19:41:00 +08:00
if coros := [
run_coro_with_catch (
proc (
matcher = matcher ,
exception = exception ,
bot = bot ,
event = event ,
state = matcher . state ,
stack = stack ,
dependency_cache = dependency_cache ,
2021-11-22 23:21:26 +08:00
) ,
2022-08-14 19:41:00 +08:00
( SkippedException , ) ,
2021-11-22 23:21:26 +08:00
)
2022-08-14 19:41:00 +08:00
for proc in _run_postprocessors
] :
2020-11-07 17:35:44 +08:00
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> "
)
2020-12-24 22:19:08 +08:00
if matcher . block :
2020-11-16 11:25:42 +08:00
raise StopPropagation
2020-12-05 20:32:38 +08:00
return
2020-08-21 14:24:32 +08:00
2021-09-27 12:52:21 +08:00
async def handle_event ( bot : " Bot " , event : " Event " ) - > None :
2022-01-18 23:46:10 +08:00
""" 处理一个事件。调用该函数以实现分发事件。
2020-11-30 11:08:00 +08:00
2022-01-12 18:31:12 +08:00
参数 :
2022-01-12 19:10:29 +08:00
bot : Bot 对象
event : Event 对象
2020-11-30 11:08:00 +08:00
2022-01-12 18:53:30 +08:00
用法 :
` ` ` python
2020-11-16 15:06:37 +08:00
import asyncio
asyncio . create_task ( handle_event ( bot , event ) )
2022-01-12 18:53:30 +08:00
` ` `
2020-11-16 15:06:37 +08:00
"""
2020-10-29 17:06:07 +08:00
show_log = True
2022-09-09 11:52:57 +08:00
log_msg = f " <m> { escape_tag ( bot . type ) } { escape_tag ( bot . self_id ) } </m> | "
2020-12-09 17:51:24 +08:00
try :
2020-12-19 14:16:47 +08:00
log_msg + = event . get_log_string ( )
2020-12-09 17:51:24 +08:00
except NoLogException :
2020-10-29 17:06:07 +08:00
show_log = False
if show_log :
2021-04-19 21:15:10 +08:00
logger . opt ( colors = True ) . success ( log_msg )
2020-08-25 18:02:18 +08:00
2021-11-21 12:36:44 +08:00
state : Dict [ Any , Any ] = { }
2021-12-16 23:22:25 +08:00
dependency_cache : T_DependencyCache = { }
2020-07-04 22:51:10 +08:00
2021-11-15 21:44:24 +08:00
async with AsyncExitStack ( ) as stack :
2022-08-14 19:41:00 +08:00
if coros := [
run_coro_with_catch (
proc (
bot = bot ,
event = event ,
state = state ,
stack = stack ,
dependency_cache = dependency_cache ,
2021-11-22 23:21:26 +08:00
) ,
2022-08-14 19:41:00 +08:00
( SkippedException , ) ,
2021-11-22 23:21:26 +08:00
)
2022-08-14 19:41:00 +08:00
for proc in _event_preprocessors
] :
2021-11-15 21:44:24 +08:00
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> "
2021-03-27 14:42:43 +08:00
)
2021-11-15 21:44:24 +08:00
return
except Exception as e :
logger . opt ( colors = True , exception = e ) . error (
" <r><bg #f8bbd0>Error when running EventPreProcessors. "
2021-11-22 23:21:26 +08:00
" Event ignored!</bg #f8bbd0></r> "
)
2021-11-15 21:44:24 +08:00
return
# Trie Match
2021-12-27 02:26:02 +08:00
try :
TrieRule . get_value ( bot , event , state )
except Exception as e :
logger . opt ( colors = True , exception = e ) . warning (
" Error while parsing command for event "
)
2021-11-15 21:44:24 +08:00
break_flag = False
for priority in sorted ( matchers . keys ( ) ) :
if break_flag :
break
2020-11-07 17:35:44 +08:00
2021-03-27 14:42:43 +08:00
if show_log :
2021-11-15 21:44:24 +08:00
logger . debug ( f " Checking for matchers in priority { priority } ... " )
pending_tasks = [
2021-11-22 23:21:26 +08:00
_check_matcher (
priority , matcher , bot , event , state . copy ( ) , stack , dependency_cache
)
2021-11-15 21:44:24 +08:00
for matcher in matchers [ priority ]
]
2021-11-22 23:21:26 +08:00
results = await asyncio . gather ( * pending_tasks , return_exceptions = True )
2021-11-15 21:44:24 +08:00
for result in results :
if not isinstance ( result , Exception ) :
continue
if isinstance ( result , StopPropagation ) :
break_flag = True
logger . debug ( " Stop event propagation " )
else :
logger . opt ( colors = True , exception = result ) . error (
" <r><bg #f8bbd0>Error when checking Matcher.</bg #f8bbd0></r> "
)
2022-08-14 19:41:00 +08:00
if coros := [
run_coro_with_catch (
proc (
bot = bot ,
event = event ,
state = state ,
stack = stack ,
dependency_cache = dependency_cache ,
2021-11-22 23:21:26 +08:00
) ,
2022-08-14 19:41:00 +08:00
( SkippedException , ) ,
2021-11-22 23:21:26 +08:00
)
2022-08-14 19:41:00 +08:00
for proc in _event_postprocessors
] :
2021-11-15 21:44:24 +08:00
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> "
)