|
|
# 导入logging模块,用于记录钩子系统运行过程中的日志(如注册信息、错误信息等)
|
|
|
import logging
|
|
|
|
|
|
# 创建当前模块的日志记录器,日志名称与模块绑定,便于区分不同组件的日志输出
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# 全局钩子存储字典,用于保存所有注册的钩子及其对应的回调函数
|
|
|
# 键:钩子名称(字符串,如"article_create")
|
|
|
# 值:回调函数列表(所有注册到该钩子的可调用对象将按注册顺序存储)
|
|
|
_hooks = {}
|
|
|
|
|
|
|
|
|
def register(hook_name: str, callback: callable):
|
|
|
"""
|
|
|
注册一个钩子回调函数,将其添加到指定钩子名称对应的回调列表中
|
|
|
|
|
|
核心作用:建立"钩子名称"与"处理逻辑(回调函数)"的映射关系,
|
|
|
使后续触发钩子时能自动执行所有注册的回调
|
|
|
|
|
|
:param hook_name: 钩子名称(字符串),需与触发时使用的名称一致(如ARTICLE_CREATE)
|
|
|
:param callback: 可调用对象(函数、方法等),当钩子被触发时会执行此对象
|
|
|
回调函数的参数需与钩子触发时传递的参数匹配
|
|
|
"""
|
|
|
# 若钩子名称尚未在全局字典中,初始化一个空列表用于存储回调
|
|
|
if hook_name not in _hooks:
|
|
|
_hooks[hook_name] = []
|
|
|
# 将回调函数添加到对应钩子的列表中(按注册顺序存储,触发时也按此顺序执行)
|
|
|
_hooks[hook_name].append(callback)
|
|
|
# 记录DEBUG级日志,说明钩子注册成功(包含钩子名称和回调函数名,便于调试)
|
|
|
logger.debug(f"Registered hook '{hook_name}' with callback '{callback.__name__}'")
|
|
|
|
|
|
|
|
|
def run_action(hook_name: str, *args, **kwargs):
|
|
|
"""
|
|
|
执行指定名称的"动作钩子(Action Hook)",按注册顺序调用所有关联的回调函数
|
|
|
|
|
|
动作钩子特性:用于触发一系列操作,不关注返回值,仅执行回调逻辑
|
|
|
典型场景:文章创建后发送通知、记录日志等(执行动作但无需修改数据)
|
|
|
|
|
|
:param hook_name: 要触发的钩子名称(需已被注册过)
|
|
|
:param *args: 传递给回调函数的位置参数(可变参数,根据钩子场景定义)
|
|
|
:param **kwargs: 传递给回调函数的关键字参数(可变参数,根据钩子场景定义)
|
|
|
"""
|
|
|
# 检查该钩子是否有已注册的回调函数
|
|
|
if hook_name in _hooks:
|
|
|
# 记录DEBUG级日志,说明开始执行该动作钩子
|
|
|
logger.debug(f"Running action hook '{hook_name}'")
|
|
|
# 按注册顺序遍历所有回调函数并执行
|
|
|
for callback in _hooks[hook_name]:
|
|
|
try:
|
|
|
# 传递位置参数和关键字参数给回调函数
|
|
|
callback(*args, **kwargs)
|
|
|
except Exception as e:
|
|
|
# 若回调执行出错,记录ERROR级日志(包含详细异常信息)
|
|
|
# exc_info=True 会在日志中附带堆栈跟踪,便于排查错误
|
|
|
logger.error(
|
|
|
f"Error running action hook '{hook_name}' callback '{callback.__name__}': {e}",
|
|
|
exc_info=True
|
|
|
)
|
|
|
|
|
|
|
|
|
def apply_filters(hook_name: str, value, *args, **kwargs):
|
|
|
"""
|
|
|
执行指定名称的"过滤钩子(Filter Hook)",通过回调函数链式处理初始值并返回最终结果
|
|
|
|
|
|
过滤钩子特性:用于对数据进行加工处理,每个回调函数接收上一个函数的输出作为输入,
|
|
|
最终返回经过所有回调处理后的值
|
|
|
典型场景:文章内容过滤敏感词、格式化文本等(修改数据并返回新值)
|
|
|
|
|
|
:param hook_name: 要触发的钩子名称(需已被注册过)
|
|
|
:param value: 初始值(需要被过滤/处理的数据,如文章内容字符串)
|
|
|
:param *args: 传递给回调函数的额外位置参数
|
|
|
:param **kwargs: 传递给回调函数的额外关键字参数
|
|
|
:return: 经过所有回调函数处理后的最终值
|
|
|
"""
|
|
|
# 检查该钩子是否有已注册的回调函数
|
|
|
if hook_name in _hooks:
|
|
|
# 记录DEBUG级日志,说明开始执行该过滤钩子
|
|
|
logger.debug(f"Applying filter hook '{hook_name}'")
|
|
|
# 按注册顺序遍历所有回调函数,链式处理初始值
|
|
|
for callback in _hooks[hook_name]:
|
|
|
try:
|
|
|
# 调用回调函数,将当前值和额外参数传入,更新值为回调返回的结果
|
|
|
value = callback(value, *args, **kwargs)
|
|
|
except Exception as e:
|
|
|
# 若回调执行出错,记录ERROR级日志(包含详细异常信息)
|
|
|
logger.error(
|
|
|
f"Error applying filter hook '{hook_name}' callback '{callback.__name__}': {e}",
|
|
|
exc_info=True
|
|
|
)
|
|
|
# 返回经过所有过滤处理后的最终值
|
|
|
return value |