Files
WechatHookBot/docs/MemoryBank/03-技术要点.md
2025-12-03 15:48:44 +08:00

235 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 技术要点
## 核心架构
### 1. DLL Hook 机制
**工作流程**:
```
1. 加载 Loader.dll
2. 创建共享内存 (关键!)
3. 注册 Socket 回调
4. 调用 InjectWeChat 注入 Helper.dll
5. 等待 Socket 连接回调
6. 使用 Socket Client ID 发送 API 请求
```
**关键代码**:
```python
# 共享内存创建 (必须在 Loader 之前)
create_shared_memory()
# 注册回调
add_callback_handler(self)
loader = NoveLoader(loader_dll)
# 注入微信
process_id = loader.InjectWeChat(helper_dll)
# 等待 Socket 连接
# socket_client_id 从回调中获取 (通常为 1)
# 使用 Socket ID 发送请求
client = WechatHookClient(loader, socket_client_id)
```
### 2. 消息类型映射
**实际测试的消息类型**:
```python
MT_DEBUG_LOG = 11024 # 调试日志
MT_USER_LOGIN = 11025 # 用户登录 (自动推送)
MT_TEXT = 11046 # 文本消息
MT_IMAGE = 11047 # 图片消息
MT_VOICE = 11048 # 语音消息
MT_VIDEO = 11049 # 视频消息
MT_EMOJI = 11050 # 表情消息
MT_LOCATION = 11051 # 位置消息
MT_LINK = 11052 # 链接消息
MT_FILE = 11053 # 文件消息
MT_MINIAPP = 11054 # 小程序消息
MT_CARD = 11055 # 名片消息
MT_FRIEND_REQUEST = 11056 # 好友请求
MT_REVOKE = 11057 # 撤回消息
MT_SYSTEM = 11058 # 系统消息
```
### 3. 消息数据结构
**文本消息** (type=11046):
```json
{
"at_user_list": [],
"from_wxid": "wxid_xxx",
"is_pc": 0,
"msg": "消息内容",
"msgid": "123456789",
"room_wxid": "",
"timestamp": 1762940000,
"to_wxid": "wxid_yyy",
"wx_type": 1
}
```
**登录信息** (type=11025):
```json
{
"account": "账号",
"avatar": "http://...",
"device_id": "设备ID",
"nickname": "昵称",
"phone": "手机号",
"wxid": "wxid_xxx",
"wx_user_dir": "C:\\..."
}
```
### 4. 群聊消息判断
**关键字段**:
- `room_wxid`: 群聊 ID私聊时为空
- `from_wxid`: 发送者 wxid
- `to_wxid`: 接收者 (群聊时是群 ID)
**判断逻辑**:
```python
room_wxid = data.get("room_wxid", "")
if room_wxid:
# 群聊消息
message["IsGroup"] = True
message["FromWxid"] = room_wxid
message["SenderWxid"] = data.get("from_wxid", "")
else:
# 私聊消息
message["IsGroup"] = False
message["FromWxid"] = data.get("from_wxid", "")
```
### 5. 异步回调处理
**问题**: 回调在同步线程中执行,但需要调用异步方法
**解决方案**:
```python
# 在初始化时保存事件循环
self.event_loop = asyncio.get_event_loop()
# 在回调中使用
asyncio.run_coroutine_threadsafe(
self.hookbot.process_message(msg_type, data),
self.event_loop
)
```
### 6. 插件系统
**插件生命周期**:
```python
class MyPlugin(PluginBase):
def __init__(self):
super().__init__()
# 初始化成员变量
async def async_init(self):
# 异步初始化 (加载配置等)
pass
async def on_enable(self, bot=None):
# 启用时调用 (注册定时任务)
pass
async def on_disable(self):
# 禁用时调用 (清理资源)
pass
```
**事件处理**:
```python
@on_text_message()
async def handle_message(self, bot, message: dict):
content = message.get("Content", "")
from_wxid = message.get("FromWxid", "")
# 处理消息
await bot.send_text(from_wxid, "回复内容")
```
## 常见问题
### Q1: 为什么必须使用 32 位 Python?
**A**: Loader.dll 和 Helper.dll 是 32 位编译的,只能在 32 位 Python 中加载。
### Q2: 为什么需要共享内存?
**A**: DLL 之间通过共享内存进行通信,必须在加载 Loader.dll 之前创建。
### Q3: 为什么 Socket Client ID 和进程 ID 不同?
**A**:
- `InjectWeChat` 返回的是微信进程 ID
- 回调中的 `client_id` 是 Socket 连接 ID (从 1 开始)
- 发送 API 请求时使用 Socket ID
### Q4: 如何判断是群聊还是私聊?
**A**: 检查 `room_wxid` 字段,不为空则是群聊。
### Q5: 插件配置为什么没有加载?
**A**: 使用 `async_init` 方法而不是 `on_load`
### Q6: 如何热重载插件?
**A**: 发送 `/重载插件 插件名` 命令。
### Q7: 为什么收不到消息?
**A**: 检查以下几点:
1. 共享内存是否创建成功
2. Socket 客户端是否连接
3. 消息类型是否在 MESSAGE_TYPE_MAP 中
4. 消息是否被过滤 (白名单/黑名单)
### Q8: 如何添加新的消息类型?
**A**:
1.`message_types.py` 中添加常量
2.`MESSAGE_TYPE_MAP` 中添加映射
3.`normalize_message` 中处理特殊字段
## 性能优化
### 1. 消息处理
- 使用 `asyncio.run_coroutine_threadsafe` 避免阻塞回调线程
- 深拷贝消息数据避免并发问题
### 2. 插件管理
- 按优先级排序事件处理器
- 支持插件返回 False 中断处理链
### 3. 错误处理
- 每个处理器独立 try-except
- 一个插件出错不影响其他插件
## 调试技巧
### 1. 查看回调数据
```python
logger.info(f"[回调] 收到消息: type={msg_type}, data={msg_data}")
```
### 2. 查看消息处理
```python
logger.info(f"收到消息: type={event_type}, from={from_wxid}, content={content}")
```
### 3. 查看插件加载
```python
logger.info(f"插件 {plugin_name} 已加载")
```
### 4. 使用调试日志
```python
logger.debug(f"详细信息: {variable}")
```
## 安全注意事项
1. **API 密钥**: 不要将 API 密钥提交到版本控制
2. **管理员权限**: 只有管理员可以执行插件管理命令
3. **消息过滤**: 使用白名单/黑名单控制消息处理
4. **错误处理**: 捕获所有异常避免崩溃