aboutsummaryrefslogtreecommitdiff
path: root/docs/_zh_CN/pages/13-hook.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/_zh_CN/pages/13-hook.md')
-rw-r--r--docs/_zh_CN/pages/13-hook.md107
1 files changed, 107 insertions, 0 deletions
diff --git a/docs/_zh_CN/pages/13-hook.md b/docs/_zh_CN/pages/13-hook.md
new file mode 100644
index 0000000..543ee55
--- /dev/null
+++ b/docs/_zh_CN/pages/13-hook.md
@@ -0,0 +1,107 @@
+<h1 align="center">钩子系统</h1>
+<p align="center">
+ 如何使用 ProgramHook 向程序内部插入行为
+</p>
+
+Hook 让你在管线的各个生命周期节点插入自定义逻辑 —— 在 dispatch 之前、chain 之后、render 前后、程序退出时 ……
+
+你可以把横切关注点(日志、鉴权、指标收集)写在 hook 里,而不是散落在各处的业务代码中。
+
+## 基本用法
+
+`ProgramHook` 采用 builder 模式构造:
+
+```rust
+@@@use mingling::hook::ProgramHook;
+fn main() {
+ let mut program = ThisProgram::new();
+ program.with_hook(
+ ProgramHook::empty()
+ .on_pre_chain(|info| {
+ println!("before chain: {}", info.input);
+ })
+ .on_post_render(|info| {
+ println!("after render: {}", info.result);
+ }),
+ );
+ program.exec_and_exit();
+}
+```
+
+> [!TIP]
+> `ProgramHook::empty()` 创建一个空 hook,然后链式调用 `.on_*()` 方法注册你关心的生命周期节点。没有注册的节点不会执行。
+
+## 生命周期节点
+
+Hook 覆盖了管线的完整生命周期:
+
+| 阶段 | Hook | 触发时机 |
+| ------------ | ------------------ | ------------- |
+| **Dispatch** | `on_begin` | 执行开始 |
+| | `on_pre_dispatch` | Dispatch 之前 |
+| | `on_post_dispatch` | Dispatch 之后 |
+| **Chain** | `on_pre_chain` | Chain 执行前 |
+| | `on_post_chain` | Chain 执行后 |
+| **Render** | `on_pre_render` | Render 执行前 |
+| | `on_post_render` | Render 执行后 |
+| **Finish** | `on_finish` | 程序退出前 |
+
+每个 hook 回调接收对应的 `Hook*Info` 结构体,里面包含当前上下文的信息(输入类型、参数、渲染结果等)。
+
+## 实际例子:记录操作日志
+
+```rust
+@@@use mingling::prelude::*;
+@@@use mingling::hook::ProgramHook;
+@@@
+@@@dispatcher!("greet", CMDGreet => EntryGreet);
+@@@pack!(ResultName = String);
+@@@
+@@@#[chain] fn handle_greet(args: EntryGreet) -> Next {
+@@@ ResultName::new(args.inner.first().cloned().unwrap_or_default()).to_render()
+@@@}
+@@@#[renderer] fn render_name(r: ResultName) { r_println!("Hello, {}!", *r); }
+fn main() {
+ let mut program = ThisProgram::new();
+
+ // 记录每次 chain 执行前后的信息
+ program.with_hook(
+ ProgramHook::empty()
+ .on_pre_chain(|info| {
+ eprintln!("[hook] executing chain for: {}", info.input);
+ })
+ .on_post_chain(|info| {
+ eprintln!("[hook] chain output: {}", info.output.member_id);
+ }),
+ );
+
+ program.with_dispatcher(CMDGreet);
+ program.exec_and_exit();
+}
+```
+
+运行效果:
+
+```text
+[hook] executing chain for: EntryGreet
+[hook] chain output: ResultName
+Hello, World!
+```
+
+## 通过 Hook 控制行为
+
+Hook 不仅用来 "看",还可以用 `ProgramControlUnit` 改变程序行为:
+
+| 变体 | 效果 |
+| -------------------------- | ----------------------------------------- |
+| `Continue` | 什么都不做,继续执行 |
+| `OverrideExitCode(i32)` | 覆盖退出码 |
+| `RouteToChain(AnyOutput)` | 将当前数据替换为新的,重新进入 Chain 循环 |
+| `RouteToRender(AnyOutput)` | 跳过后续 Chain,直接渲染 |
+
+> [!NOTE]
+> Hook 可以注册多个,按注册顺序执行。
+
+<p align="center" style="font-size: 0.85em; color: gray;">
+ Written by @Weicao-CatilGrass
+</p>