feat:初版

This commit is contained in:
2025-12-03 15:48:44 +08:00
commit b4df26f61d
199 changed files with 23434 additions and 0 deletions

View File

@@ -0,0 +1,234 @@
# 技术要点
## 核心架构
### 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. **错误处理**: 捕获所有异常避免崩溃