Skip to content

Bus 消息总线

它是什么

Bus 是洛玖的核心通信机制。所有消息——不管是 QQ 消息、通知、还是插件发的回复——都通过它传递。

你可以把它想象成一个邮局系统:每个 topic 是一个信箱,每个插件在信箱里有自己的格子。

Topic

消息按 topic 分类。每个 topic 有独立的队列,互不干扰。

Topic方向用途
luo9_message宿主 → 插件QQ 消息
luo9_meta_event宿主 → 插件心跳、生命周期
luo9_notice宿主 → 插件好友/群变动
luo9_request宿主 → 插件好友/群请求
luo9_task宿主 → 插件定时任务触发
luo9_task_miso插件 → 宿主创建/取消任务
luo9_send插件 → 宿主请求发送消息
luo9_version宿主 → 插件版本查询
luo9_version_reply插件 → 宿主版本响应

Subscriber

每个插件在每个 topic 上有独立的 subscriber。消息不会被其他插件抢走。

当 subscriber 被取消订阅时(比如插件被禁用),会收到一个特殊的哨兵消息 __luo9_unsubscribed__。收到它就该退出循环了。

用法

订阅

rust
let sub_id = Bus::topic("luo9_message").subscribe().unwrap();

取消息

rust
// 非阻塞,没消息就返回 None
match Bus::topic("luo9_message").pop(sub_id) {
    Some(msg) => { /* 处理消息 */ }
    None => { /* 没消息,干别的去 */ }
}

// 阻塞,等到有消息才返回
match Bus::topic("luo9_message").wait_pop(sub_id) {
    Ok(msg) => { /* 处理消息 */ }
    Err(BusError::Unsubscribed) => { /* 被取消订阅了,退出 */ }
    Err(e) => { /* 出错了 */ }
}

多 topic 的插件用 pop + sleep 轮询;只订阅一个 topic 的可以用 wait_pop

发消息

rust
// 广播给所有订阅者
Bus::topic("luo9_send").publish(r#"{"action":"send_group_msg","group_id":123,"message":"hello"}"#)?;

// 只发给指定的 subscriber
Bus::topic("luo9_message").publish_to("targeted_msg", &[1, 3, 5])?;

性能

  • 无界队列:消息不会丢,但积压太多会吃内存
  • Per-topic 并发:不同 topic 互不阻塞
  • 阻塞等待wait_pop 用 Condvar 实现,不占 CPU

基于 GPLv3 许可发布