Skip to content

信号总线

插件通过 Component trait 注册到总线,使用 BusContext 与其他组件通信。

实现组件

rust
use std::any::TypeId;
use foxcore_api::*;

struct MyComponent;

#[async_trait::async_trait]
impl Component for MyComponent {
    fn id(&self) -> &'static str {
        "my_component"
    }

    // 声明接受哪些类型的广播消息
    fn accepts(&self) -> &'static [TypeId] {
        &[]  // 空 = 只接受点对点消息
    }

    async fn handle(&self, mut packet: AnyPacket, ctx: &BusContext) -> Result<(), BusError> {
        // 尝试将包解析为具体类型
        if let Some(msg) = packet.downcast_ref::<String>() {
            tracing::info!("收到消息:{msg}");
        }

        // 如果需要回复
        if let Some(reply) = packet.take_reply() {
            reply.send(AnyPacket::new("pong")).await.ok();
        }

        Ok(())
    }

    async fn on_start(&self, _ctx: &BusContext) -> Result<(), BusError> {
        tracing::info!("组件已启动");
        Ok(())
    }

    async fn on_stop(&self) -> Result<(), BusError> {
        tracing::info!("组件已停止");
        Ok(())
    }
}

通信方式

通过 BusContext 提供三种通信模式:

广播

发送给所有接受该类型的组件:

rust
ctx.broadcast(MyEvent { ... }).await?;

点对点

发送给指定组件:

rust
ctx.emit_to("target_component", MyData { ... }).await?;

请求-响应

发送并等待回复:

rust
let reply = ctx.request("target", MyQuery { ... }).await?;
let result = reply.downcast_ref::<MyResult>().unwrap();

流式响应

获取多个回复:

rust
let mut rx = ctx.request_stream("target", query, 8).await?;
while let Some(packet) = rx.recv().await {
    // 处理每个响应
}

适配器桥接

组件无需直接访问适配器,通过 BusContext 快捷方法间接调用:

rust
use foxcore_api::message::*;
use serde_json::json;

// 发送消息
ctx.send_message(OutgoingMessage {
    context: MessageContext::Group { group_id: "123456".into() },
    target_id: None,
    segments: vec![MessageSegment::Text { text: "Hello!".into() }],
}).await?;

// 调用平台 API
ctx.call_adapter_api("delete_msg", json!({"message_id": 12345})).await?;

生命周期

  1. on_start — 总线启动时调用,按注册顺序执行
  2. handle — 收到消息时调用
  3. on_stop — 总线关闭时调用,按注册逆序执行

如果某个组件 on_start 失败,已启动的组件会按逆序 on_stop 回滚。