# ek-core
**Actor-over-Bus 插件宿主**。在已发布的 [ek-event](https://crates.io/crates/ek-event) 事件底座之上,提供一套业务无关的插件框架:单表注册、显式依赖、拓扑启动、独立线程 actor、一次性请求应答、故障熔断与五步关停。
> 设计立场:ek-core 不依赖任何业务;事件总线只转发、永不执行业务逻辑;插件之间不直调,一切通信走事件。
## 特性
- **统一单表注册**:`add_plugin` / `get_plugin` / `get_state` / `get_typed::<T>`(类型安全下转型),无 dual-API。
- **显式依赖**:`deps()` 声明,注册期校验存在性,`start()` 按 Kahn 拓扑序装配(环报 `DepCycle`),`close()` 逆序回收。
- **每插件一个 actor**:bounded(默认 1024,可覆写)邮箱 + 专用 `ek-worker.<name>` 线程,`on_mail` 是插件唯一收信口,天然串行化。
- **唯一出口**:`ctx.put`(广播)/ `ctx.ask<Req, Res>`(`eReq` + 一次性信道)/ `ctx.notify`(`eTo`)/ `ctx.write_log`(内置 LogPlugin)。
- **快失败请求**:`ask` 三重失败面——目标不在(预检+断连,即时 `TargetGone`)、等满(`Timeout`)、契约不匹配(`InvalidPayload`);handler panic 时回包信道关闭 → 发起方立即感知。
- **故障熔断**:handler **连续** panic×3(处理成功即复位)→ 插件隔离为 `Quarantined`,并发 `ePlugQDown.<name>` 广播 + eLog 双告警;邻居插件毫发无损。
- **背压可观**:邮箱满即丢弃计数 + 每 128 次溢出节流 eLog;`mail_stats` 随时可查。
- **五步关停**:卸 forwarder → `on_stop` → 关邮箱 → worker 排空 → join(带超时,超时告警绝不硬等)。
## 示例
```rust
use ek_core::{MainEngine, Plugin, PluginContext, PluginState, AskError, e_req_type};
use ek_event::Event;
use std::borrow::Cow;
use std::time::Duration;
use std::sync::Arc;
use std::any::Any;
// 合约契约类型(业务 crate 自备,ek-core 一无所知)
#[derive(Clone, Copy, Debug)] struct Ping { id: u64 }
#[derive(Clone, Copy, Debug)] struct Pong { id: u64 }
struct Broker { name: String }
impl Plugin for Broker {
fn name(&self) -> &str { &self.name }
fn routes(&self) -> Vec<Cow<'static, str>> { vec![Cow::Owned(e_req_type("broker"))] }
fn on_mail(&self, event: &Event) {
ek_core::envelope::Envelope::handle::<Ping, Pong>(event, |p| Pong { id: p.id });
}
}
struct Client {
name: String,
broker: String,
}
// ... client 在 on_mail 里(on_init 缓存 ctx):
// let r = ctx.ask::<Ping, Pong>("broker", Ping { id }, Duration::from_millis(500));
fn main() {
let engine = MainEngine::new(None);
engine.add_plugin(Arc::new(Broker { name: "broker".into() })).unwrap();
// engine.add_plugin(...) client(deps = ["broker"])
engine.start().unwrap();
// ... 收发事件 ...
engine.close_all(Duration::from_secs(2)); // 五步关停 + 停总线
}
```
## 纪律(协议层)
1. 收:只有 `on_mail` 一个入口;订阅面由 `routes()` 静态声明(v0.1 不支持运行期动态订阅)。
2. 发:只有 `ctx.put / ask / notify / write_log` 四个出口;**ask 禁止自呼**(自己等自己的回包会等到超时)。
3. 请求义务:`Envelope::handle` 成功回 `Ok(Res)`、契约错型回 `Err(InvalidPayload)`;handler panic 由断连信号传达。
4. 宿主无业务方法;管理类操作(add/remove/start/close)按串行使用设计。
## 元信息
- crate:`ek-core 0.1.0`(edition 2024,`rust-version = 1.85`)
- 依赖:`ek-event = "0.1.0"`(crates.io)+ `crossbeam-channel`(邮箱/总线同源)
- 仓库:https://cnb.cool/enkeep/ek-core
- License:MIT(见 [LICENSE.txt](LICENSE.txt))
案例设计文档:[DESIGN.md](DESIGN.md);验收细节:[TESTPLAN.md](TESTPLAN.md)。