Skip to main content

ek_station/
wire.rs

1//! svctl —— 宿主管控服务的线上契约(唯一提供方 `crate::supervisor::Supervisor`)。
2//!
3//! 契约形状(与 ek-dm/ek-ctp 的 ask 同构,三口都走 `ask_service`):
4//! - [`SVC_LIST`]:[`ListReq`] → `Vec<[`PlugRow`]>`(全插件快照一行一个)。
5//! - [`SVC_START`]:[`StartReq`] → [`StartRes`](`Started`/`Rejected` 两种业务回执,
6//!   不用 `ReplyErr` 承载业务错 —— 回执枚举在总线上可读可断言)。
7//! - [`SVC_REMOVE`]:[`RemoveReq`] → [`RemoveRes`](`Removed`/`NoSuchName`/`Rejected`
8//!   三种业务回执;`name` 栏一律保真,错因只在 `Rejected.reason`)。
9//!
10//! 语义钉(ek-core 0.3.0 能力面自然修正):宿主没有"停而不摘表"的导出,
11//! 唯一的运行期下线动作是 `remove_plugin`(五步闭停 + 摘表 + `ePlugDown` 广播),
12//! 故 stop 语义并入 [`SVC_REMOVE`];再次启用走 [`SVC_START`] 动态重新注入
13//! (宿主 add_plugin 在 start 后直接 `launch_one` 上线并广播 `ePlugUp`)。
14
15use ek_core::service::ServiceDesc;
16
17// ================ 服务 id(服务目录键,UI 侧 ask_service 用) ================
18
19/// 列出全部插件快照。
20pub const SVC_LIST: &str = "svctl.list";
21/// 按工厂名动态注入一个新插件(start 后直接上线)。
22pub const SVC_START: &str = "svctl.start";
23/// 摘除一个运行中/未装配插件(stop 语义并入;ek-core 0.3.0 无"停而不摘表"导出)。
24pub const SVC_REMOVE: &str = "svctl.remove";
25
26// ================ list ================
27
28/// 一行插件快照(观测页逐行渲染)。
29#[derive(Debug, Clone, PartialEq)]
30pub struct PlugRow {
31    /// 注册名。
32    pub name: String,
33    /// 申报版本(插件自填;空串 = 未声明)。
34    pub version: String,
35    /// 生命周期状态(Debug 形状字符串:Ready/Running/Stopping/Exited/Quarantined)。
36    pub state: String,
37    /// 显式依赖的插件名。
38    pub deps: Vec<String>,
39    /// 软顶触发的丢弃累计(0.5.0 口径:默认无界不丢,只有触到软顶才丢)。
40    pub spilled: u64,
41    /// panic 累计(连续超限 → Quarantined)。
42    pub panics: u64,
43    /// **当前邮箱深度**(0.5.0:积压读数;消费侧显示"刷新滞后"的原料)。
44    pub pending: u64,
45    /// 历史峰值(只涨不跌:这段最堵的时候留档)。
46    pub peak: u64,
47    /// 该插件自己的软顶(0.5.0:溢出判据必须吃**它自己的线**,消费侧不再自备容量表)。
48    pub soft_cap: u64,
49}
50
51/// 快照请求(无参)。
52#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
53pub struct ListReq;
54
55/// 快照回执(注册序)。
56pub type ListRes = Vec<PlugRow>;
57
58// ================ start ================
59
60/// 按工厂名注入请求。
61#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct StartReq {
63    /// 工厂名(= [`crate::factory::PlugKind`] 的 name)。
64    pub factory: String,
65    /// 实例注册名(多账号/多实例面)。
66    ///
67    /// 空 = 沿用旧行为(工厂名即注册名,单实例场景零回归)。
68    /// 非空 = 要求工厂以这个名字建实例(工厂须登记 `build_named`);
69    /// 名字合法性仍由宿主 `valid_plugin_name` 把关。
70    pub name: String,
71}
72
73/// 注入回执:业务结果自带(成功给出实际注册名;失败给原因)。
74#[derive(Debug, Clone, PartialEq, Eq)]
75pub enum StartRes {
76    /// 已上线(宿主 add_plugin 成功,start 状态下立即装配)。
77    Started {
78        /// 插件注册名(= 插件自报的 name)。
79        name: String,
80    },
81    /// 拒绝(未知工厂/重名/名字非法 —— fix 后在 UI 侧红字呈现)。
82    Rejected {
83        /// 原因文本(Debug 形状,不进日志)。
84        reason: String,
85    },
86}
87
88// ================ remove ================
89
90/// 摘除请求(=ek-core `remove_plugin`;被依赖时宿主 stderr 警告,回执仍成功)。
91#[derive(Debug, Clone, PartialEq, Eq)]
92pub struct RemoveReq {
93    /// 注册名(非工厂名)。
94    pub name: String,
95}
96
97/// 摘除回执(三种业务回执,与 [`StartRes`] 同形;不用 `ReplyErr` 承载业务错)。
98#[derive(Debug, Clone, PartialEq, Eq)]
99pub enum RemoveRes {
100    /// 已摘(五步闭停 + 摘表 + 广播 `ePlugDown`)。
101    Removed {
102        /// 被摘注册名。
103        name: String,
104    },
105    /// 表内无此名(宿主 `PluginError::UnknownName`)。
106    NoSuchName {
107        /// 原请求名(照请求回填,这一栏**不放错误文本**)。
108        name: String,
109    },
110    /// 名字在场但不可摘,或宿主另有错(0.2.11 新增,BD-UI-64)。
111    ///
112    /// 为什么要有这一档:0.2.10 之前非 `UnknownName` 的宿主错被塞进
113    /// [`NoSuchName`](RemoveRes::NoSuchName),而那一栏的 `name` 文档写明是
114    /// 「原请求名」—— 把 `format!("{e:?}")` 塞进去就是契约违约(消费侧
115    /// 会把错误文本当名字打日志,原请求名丢失)。
116    /// 现:名字一律保真,错误进 `reason`。
117    Rejected {
118        /// 原请求名(与请求一致)。
119        name: String,
120        /// 原因文本(Debug 形状或管制面自报的口径句)。
121        reason: String,
122    },
123}
124
125// ================ 服务目录自报(supervisor.rs 用) ================
126
127/// Supervisor 的三口目录(与 `crate::supervisor::Supervisor::services` 同源)。
128pub(crate) fn svctl_services() -> Vec<ServiceDesc> {
129    vec![
130        ServiceDesc::describe::<ListReq, ListRes>(SVC_LIST, "station: list plugin rows"),
131        ServiceDesc::describe::<StartReq, StartRes>(SVC_START, "station: inject plugin by factory"),
132        ServiceDesc::describe::<RemoveReq, RemoveRes>(SVC_REMOVE, "station: remove plugin by name"),
133    ]
134}