feat(event_loop): sync + add_event_handler + Timeline::send 加密通道(M2.2/c)

新增模块:src/event_loop.rs

依赖新增:futures-util 0.3
源码增加:#![recursion_limit = "512"](matrix-sdk 类型嵌套很深)

实现要点:
  1. bootstrap::restore 拿到 Client + user_id + device_id
  2. 注册全局 SyncRoomMessageEvent handler(matrix-sdk add_event_handler 闭包模式)
  3. handler 内部:
     - 提取 m.text 文本
     - 跳过 bot 自己发的消息
     - 用 commands::parse 解析(自动处理 mention / DM 区分)
     - 用 commands::render_reply 渲染回复
     - 用 TimelineBuilder::new(room).build() 构造 Timeline
     - 用 timeline.send(RoomMessageEventContent::text_plain(...).into()) 发送
  4. 启动 long-running client.sync()(用 tokio::select! 与 ctrl-c 并发)

E2EE 不变量已实现并强制:
  -  唯一出站通道:Timeline::send(SDK 内部用 Megolm 加密)
  -  绝不使用 Room::send_raw()(明文)
  -  入站消息经 matrix-sdk 解密后是 plaintext,可直接解析

类型挑战(已解决):
  - matrix-sdk 0.18 EventHandler 通过 impl_event_handler! 宏实现,
    要求 FnOnce(Ev, ...) -> Fut 形式,不能包 Pin<Box<>>
  - matrix-sdk-crypto 内部有 !Send 类型,所以 client.sync() 不能 tokio::spawn,
    必须在当前 task 用 tokio::select! 与 ctrl-c 并发
  - 嵌套 async 闭包触发 rustc 深度限制,需要 #![recursion_limit = "512"]

cmd_run 改造:
  - 同样从 MATRIX_BOT_SECRET_PASSPHRASE 环境变量读取 passphrase
  - 用 tokio multi-thread runtime 跑 event_loop::run

CLI 实测(fake config + 缺 secret.bin):
  - 无 config → 友好错误
  - 有 config + 缺 secret.bin → '请先运行 login' 错误
  - 完整流程需真实 homeserver 才能跑通

测试:cargo test → 15 passed(11 commands + 2 config + 2 secret_store)
This commit is contained in:
Matrix Music Bot Dev
2026-07-02 21:03:56 +08:00
parent 5ea92de6b9
commit a2c9904ec3
4 changed files with 162 additions and 9 deletions
+1
View File
@@ -10,6 +10,7 @@ argon2 = "0.5.3"
async-trait = "0.1.89"
base64 = "0.22.1"
clap = { version = "4.6.1", features = ["derive", "env"] }
futures-util = "0.3.32"
getrandom = { version = "0.3", features = ["std"] }
matrix-sdk = "0.18.0"
matrix-sdk-crypto = "0.18.0"