信号总线
插件通过 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?;生命周期
on_start— 总线启动时调用,按注册顺序执行handle— 收到消息时调用on_stop— 总线关闭时调用,按注册逆序执行
如果某个组件 on_start 失败,已启动的组件会按逆序 on_stop 回滚。