Skip to content

Commit aab22f8

Browse files
committed
docs(advanced): 新增 Actions、EventHandlers、QQRichText和 QQDataCacher 模块文档
嘿嘿嘿AI真好用
1 parent 4f8cfe0 commit aab22f8

File tree

5 files changed

+1290
-22
lines changed

5 files changed

+1290
-22
lines changed

docs/.vitepress/config.mts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ export default defineConfig({
2424
{
2525
text: '深入',
2626
items: [
27+
{ text: '事件处理', link: '/advanced/event-handlers' },
28+
{ text: '操作', link: '/advanced/actions' },
29+
{ text: 'QQ富文本', link: '/advanced/rich-text' },
30+
{ text: 'QQ数据缓存', link: '/advanced/data-cache' },
2731
{ text: '插件配置', link: '/advanced/plugin-config' },
28-
{ text: '插件依赖', link: '/advanced/require-plugin' },
29-
{ text: 'QQ数据缓存', link: '/advanced/data-cache' }
32+
{ text: '插件依赖', link: '/advanced/require-plugin' }
3033
]
3134
}
3235
],

docs/advanced/actions.md

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# 操作 (Actions)
2+
3+
`Actions` 模块是 MuRainBot2 (MRB2) 框架中用于与 OneBot V11 API 进行交互的标准方式。它将每一个 OneBot API 调用封装成一个独立的 `Action` 类,提供了统一的调用接口、结果处理、异步执行和回调机制,极大地简化了插件与机器人核心功能的交互。
4+
p.s. 是对 `Lib.core.OnebotAPI.py` 的二次封装。
5+
6+
该模块位于 `Lib.utils.Actions.py`
7+
8+
## 核心概念
9+
10+
1. **Action 类:** 每个 OneBot API 端点(如 `send_private_msg`, `get_group_info`)都对应一个 `Action` 的子类(如 `Actions.SendPrivateMsg`, `Actions.GetGroupInfo`)。实例化这些类并配置好参数,就代表了一个准备执行的 API 调用。
11+
2. **执行 (`.call()`, `.call_async()`, `.call_get_result()`):** Action 对象本身不执行任何操作,直到你调用它的执行方法。
12+
* `.call()`: **同步**执行 Action。它会阻塞当前线程,直到 API 调用完成(成功或失败)。
13+
* `.call_async()`: **异步**执行 Action。它会将 Action 提交到框架的**线程池**执行,并**立即返回** Action 对象本身,不会阻塞当前线程。
14+
* `.call_get_result()`: **同步**执行 Action 并**立即返回结果** (`Result` 对象)。相当于 `.call().get_result()` 的便捷写法。
15+
3. **结果 (`Result` 对象):** 每次 Action 执行后(无论是同步还是异步完成),其结果都会被包装在一个 `Actions.Result` 对象中。这个对象清晰地表示了 API 调用是成功还是失败。
16+
* `result.is_ok`: (`bool`) 如果 API 调用成功,返回 `True`
17+
* `result.is_err`: (`bool`) 如果 API 调用过程中发生异常(如网络错误、API 返回错误码等),返回 `True`
18+
* `result.unwrap()`: 如果 `is_ok``True`,返回 API 成功的响应数据(通常是一个字典);如果 `is_err``True`,则 **引发异常**
19+
* `result.unwrap_err()`: 如果 `is_err``True`,返回捕获到的异常对象;如果 `is_ok``True`,则 **引发异常**
20+
* `result.expect(message)`: 类似 `unwrap()`,但在失败时引发带自定义 `message` 的异常。
21+
4. **获取结果 (`.get_result()`):** 用于获取 Action 执行后的 `Result` 对象。
22+
* 如果在 `.call()``.call_get_result()` 之后调用,它会立即返回已存储的 `Result`
23+
* 如果在 `.call_async()` 之后调用,它会 **阻塞当前线程**,直到异步任务完成,然后返回 `Result`
24+
* 如果 Action 从未被执行过,调用 `.get_result()` 会引发异常。
25+
5. **回调函数 (`callback`):** 可以在实例化 Action 时传入 `callback` 参数,或之后使用 `.set_callback()` 方法设置。这个函数会在 Action **执行完毕** (无论成功或失败) 后被调用,并接收 `Result` 对象作为参数。回调函数本身会在 Action 执行所在的线程(同步调用在当前线程,异步调用在线程池的某个线程)中执行。
26+
6. **自动日志:** 当 Action **成功**执行时,其对应的 `logger` 方法会被自动调用,记录一条信息级别的日志(例如,发送了什么消息给谁)。
27+
28+
## 如何使用 Actions
29+
30+
### 1. 实例化 Action
31+
32+
选择你需要的 Action 类,并传入相应的参数来创建实例。
33+
34+
```python
35+
# 准备发送一条私聊消息
36+
action_send = Actions.SendPrivateMsg(
37+
user_id=123456789,
38+
message="你好!这是一条来自 MRB2 的消息。"
39+
)
40+
41+
# 准备获取群信息
42+
action_get_group = Actions.GetGroupInfo(
43+
group_id=987654321,
44+
no_cache=True # 要求不使用缓存,获取最新信息
45+
)
46+
47+
# 准备发送带图片的消息 (使用 QQRichText 构建)
48+
rich_message = QQRichText.QQRichText(
49+
QQRichText.Text("看这张图:"),
50+
QQRichText.Image(file="file:///path/to/image.jpg") # 支持本地文件、网络 URL 或 base64(data url)
51+
)
52+
action_send_rich = Actions.SendGroupMsg(
53+
group_id=987654321,
54+
message=rich_message
55+
)
56+
```
57+
58+
### 2. 执行 Action 并处理结果
59+
60+
你有多种方式执行 Action:
61+
62+
**方式一:同步执行并检查结果 (最常用)**
63+
64+
```python
65+
# 执行发送私聊消息的操作
66+
result = action_send.call_get_result() # 同步执行并获取 Result
67+
68+
if result.is_ok:
69+
# API 调用成功
70+
response_data = result.unwrap() # 获取 API 返回的数据 (通常包含 message_id)
71+
logger.info(f"消息发送成功!消息 ID: {response_data.get('message_id')}")
72+
else:
73+
# API 调用失败
74+
error = result.unwrap_err() # 获取捕获到的异常
75+
logger.error(f"消息发送失败: {error}")
76+
```
77+
78+
**方式二:同步执行 (不立即处理结果,可用于简单触发)**
79+
80+
```python
81+
# 执行踢人操作,不关心具体结果,只关心是否执行
82+
Actions.SetGroupKick(group_id=gid, user_id=uid).call()
83+
# 注意:虽然不处理 Result,但如果 API 调用失败,错误日志仍会被框架记录。
84+
```
85+
86+
**方式三:异步执行 (不阻塞当前 Handler)**
87+
88+
```python
89+
# 异步发送一条消息,不阻塞当前事件处理流程
90+
action_notify = Actions.SendGroupMsg(group_id=gid, message="正在处理您的请求,请稍候...")
91+
action_notify.call_async() # 提交到线程池,立即返回
92+
93+
# ... 当前 Handler 可以继续执行其他逻辑 ...
94+
95+
# 如果在后续某个点需要知道异步操作的结果
96+
# result = action_notify.get_result() # 这会阻塞,直到异步任务完成
97+
# if result.is_ok:
98+
# logger.info("异步通知发送完成")
99+
```
100+
101+
**方式四:使用回调函数**
102+
103+
```python
104+
def my_callback(result: Actions.Result):
105+
"""Action 完成后会被调用的函数"""
106+
if result.is_ok:
107+
logger.info(f"回调:操作成功,结果: {result.unwrap()}")
108+
else:
109+
logger.warning(f"回调:操作失败,错误: {result.unwrap_err()}")
110+
111+
# 实例化时传入回调
112+
action_with_cb = Actions.GetLoginInfo(callback=my_callback)
113+
action_with_cb.call() # 同步执行,执行完后调用 my_callback
114+
115+
# 或者异步执行带回调
116+
action_async_cb = Actions.GetFriendList().set_callback(my_callback) # 先设置回调
117+
action_async_cb.call_async() # 异步执行,执行完后在线程池中调用 my_callback
118+
```
119+
120+
### 3. 方法链式调用
121+
122+
大部分 Action 方法(如 `.call()`, `.call_async()`, `.set_callback()`, `.wait_async()`)返回 Action 对象本身,允许链式调用。
123+
124+
```python
125+
# 异步调用并等待完成,然后获取结果
126+
result = Actions.GetStatus().call_async().wait_async().get_result()
127+
128+
# 同步调用并设置回调
129+
Actions.CleanCache().set_callback(lambda res: logger.info("缓存清理完成")).call()
130+
```
131+
132+
## `Result` 对象详解
133+
134+
`Result` 对象是处理 Action 执行结果的关键。
135+
136+
```python
137+
result = Actions.SomeAction(...).call_get_result()
138+
139+
# 检查成功/失败
140+
if result.is_ok:
141+
# 安全地获取成功结果
142+
success_data = result.unwrap()
143+
print(f"成功: {success_data}")
144+
try:
145+
# 尝试获取错误会失败
146+
error = result.unwrap_err()
147+
except Exception as e:
148+
print(f"在 Ok 值上调用 unwrap_err 引发异常: {e}")
149+
elif result.is_err:
150+
# 安全地获取错误信息
151+
error_obj = result.unwrap_err()
152+
print(f"失败: {error_obj}")
153+
try:
154+
# 尝试获取成功结果会失败
155+
data = result.unwrap()
156+
except Exception as e:
157+
print(f"在 Err 值上调用 unwrap 引发异常: {e}")
158+
159+
# 或者使用 expect 获取成功结果,失败时提供自定义消息
160+
try:
161+
data = result.expect("API 调用必须成功!")
162+
except Exception as e:
163+
print(f"Expect 失败: {e}") # 会打印 "API 调用必须成功!"
164+
```
165+
166+
## 可用的 Actions 列表
167+
168+
请查看 [Onebot11文档](https://github.com/botuniverse/onebot-11/blob/master/api/public.md)
169+
170+
## 完整示例
171+
172+
```python
173+
from Lib import *
174+
import time
175+
176+
# --- 插件信息 ---
177+
plugin_info = PluginManager.PluginInfo(
178+
NAME="Action示例",
179+
AUTHOR="Xiaosu",
180+
VERSION="1.0",
181+
DESCRIPTION="演示 Actions 模块的各种用法"
182+
)
183+
184+
logger = Logger.get_logger()
185+
186+
# --- Matcher: 监听特定命令 ---
187+
cmd_rule = EventHandlers.CommandRule("action_test")
188+
matcher = EventHandlers.on_event(EventClassifier.MessageEvent, rules=[cmd_rule])
189+
190+
# --- Handler ---
191+
@matcher.register_handler()
192+
def handle_action_test(event_data: EventClassifier.MessageEvent):
193+
194+
user_id = event_data.user_id
195+
reply_prefix = QQRichText.Reply(event_data.message_id)
196+
197+
# --- 示例 1: 同步发送消息并处理结果 ---
198+
logger.info("示例1:同步发送消息")
199+
send_result = Actions.SendMsg(
200+
user_id=user_id if event_data.message_type == 'private' else -1,
201+
group_id=event_data.get("group_id", -1) if event_data.message_type == 'group' else -1,
202+
message=QQRichText.QQRichText(reply_prefix, "测试同步发送...")
203+
).call_get_result()
204+
205+
if send_result.is_ok:
206+
msg_id = send_result.unwrap().get('message_id')
207+
logger.info(f"同步消息发送成功, msg_id: {msg_id}")
208+
# --- 示例 2: 延迟撤回消息 (异步) ---
209+
logger.info("示例2:5秒后异步撤回消息")
210+
Actions.DeleteMsg(message_id=msg_id).call_async() # 提交异步撤回,但不等待
211+
# 这里需要注意,如果希望准确在5秒后撤回,需要更精确的定时机制
212+
# 简单的演示是直接异步调用
213+
else:
214+
logger.error(f"同步消息发送失败: {send_result.unwrap_err()}")
215+
216+
# --- 示例 3: 异步获取信息并使用回调 ---
217+
logger.info("示例3:异步获取群列表并使用回调")
218+
def group_list_callback(result: Actions.Result):
219+
if result.is_ok:
220+
groups = result.unwrap()
221+
group_count = len(groups)
222+
logger.info(f"回调:成功获取群列表,共 {group_count} 个群")
223+
# 在回调中再次发起 Action (例如通知用户)
224+
Actions.SendMsg(
225+
user_id=user_id if event_data.message_type == 'private' else -1,
226+
group_id=event_data.get("group_id", -1) if event_data.message_type == 'group' else -1,
227+
message=f"我加入了 {group_count} 个群聊哦!"
228+
).call() # 在回调中通常也使用同步调用,因为它已在线程池中
229+
else:
230+
logger.error(f"回调:获取群列表失败: {result.unwrap_err()}")
231+
232+
Actions.GetGroupList(callback=group_list_callback).call_async()
233+
234+
# --- 示例 4: 同步获取信息并处理 ---
235+
logger.info("示例4:同步获取登录信息")
236+
login_info_result = Actions.GetLoginInfo().call_get_result()
237+
try:
238+
login_info = login_info_result.unwrap() # 如果失败会抛出异常
239+
logger.info(f"当前登录账号:{login_info.get('nickname')} ({login_info.get('user_id')})")
240+
except Exception as e:
241+
logger.error(f"获取登录信息失败: {e}") # e 就是 Result.unwrap_err() 的内容
242+
243+
# Handler 结束,异步任务可能仍在后台执行
244+
```

0 commit comments

Comments
 (0)