Skip to main content

ek_core/
context.rs

1//! `PluginContext` —— 插件的唯一出口(put / ask / notify / write_log / 发现四问)。
2//!
3//! 纪律(P-H2 审核修订):不暴露 event_engine() 访问器——插件不许自装 handler
4//! 绕过 worker/熔断/背压;收信口(on_mail)与发信口(ctx)各只有一个。
5//!
6//! 0.2.0 新增(宿主最小知识原则):plugins / services_of / find_service /
7//! ask_service / publish_services —— 宿主只持【纯路由索引】,
8//! 方法细节住回插件本身,按需现场取(memoize 仅为性能缓存)。
9
10use crate::envelope::{e_req_type, e_to_type, Envelope, OneshotErr, ReplyErr};
11use crate::error::AskError;
12use crate::log_plugin::{LogData, EVENT_LOG, EVENT_SRV_CHG, EVENT_SRV_CHG_PREFIX};
13use crate::main_engine::{PluginInfo, PluginState};
14use crate::registry::Registry;
15use crate::service::{ProviderRef, ServiceDesc};
16use ek_event::{Event, EventEngine, PutError};
17use std::any::{Any, type_name};
18use std::sync::Arc;
19use std::time::Duration;
20
21/// 发放到插件的上下文(on_init 传入;`Clone` 供插件自存)。
22#[derive(Clone)]
23pub struct PluginContext {
24    pub(crate) event: Arc<EventEngine>,
25    pub(crate) registry: Arc<Registry>,
26    pub(crate) name: String,
27}
28
29impl PluginContext {
30    pub(crate) fn new(event: Arc<EventEngine>, registry: Arc<Registry>, name: String) -> Self {
31        Self { event, registry, name }
32    }
33
34    /// 本插件注册名。
35    pub fn name(&self) -> &str {
36        &self.name
37    }
38
39    /// 广播出口:插件自发事件(业务 broadcast / eTo / eLog 均经此)。
40    pub fn put(&self, event: Event) -> Result<(), PutError> {
41        self.event.put(event)
42    }
43
44    /// 日志出口(eLog → 内置 LogPlugin)。
45    pub fn write_log(&self, level: u8, msg: &str) {
46        let data = LogData {
47            level,
48            source: self.name.clone(),
49            msg: msg.to_string(),
50        };
51        let _ = self.event.put(Event::with_data(EVENT_LOG, Arc::new(data)));
52    }
53
54    /// 定向通知出口:eTo.<target>,无回包;目标不在线时事件被静默分发为空(尽力而为)。
55    pub fn notify(&self, target: &str, payload: Arc<dyn Any + Send + Sync>) {
56        let _ = self.event.put(Event::with_data(e_to_type(target), payload));
57    }
58
59    // ================ 服务发现四问(0.2.0) ================
60
61    /// 枚举宿主内全部插件(含 Ready;快照含版本)。
62    pub fn plugins(&self) -> Vec<PluginInfo> {
63        let mut out = Vec::new();
64        for name in self.registry.names() {
65            if let Some(info) = self.registry.info_of(&name) {
66                out.push(info);
67            }
68        }
69        out
70    }
71
72    /// 某插件自报的完整服务目录(现场取 + 世代核对 + memoize)。
73    /// Ready 未 Running 亦可查(声明在注册时即静态可用)。
74    /// 该插件不存在 → None。
75    pub fn services_of(&self, name: &str) -> Option<Arc<Vec<ServiceDesc>>> {
76        self.registry.services_of(name)
77    }
78
79    /// 按【服务 id】全宿主查找提供方(有序:注册序;含非 Running 状态 → 供消费方自裁)。
80    /// A 不需要预先知道提供方的注册名。
81    pub fn find_service(&self, svc: &str) -> Vec<ProviderRef> {
82        let mut out = Vec::new();
83        for name in self.registry.index_providers(svc) {
84            let Some(list) = self.registry.services_of(&name) else { continue };
85            let Some(entry) = self.registry.get(&name) else { continue };
86            if let Some(desc) = list.iter().find(|d| d.id == svc) {
87                out.push(ProviderRef {
88                    name: entry.name.clone(),
89                    version: entry.plugin.version().into_owned(),
90                    state: entry.state.get(),
91                    service: desc.clone(),
92                });
93            }
94        }
95        out
96    }
97
98    /// 运行期重新申报自己的服务目录:宿主重织索引、作废缓存,双发 `eSrvChg.<名>`(版本串)
99    /// 与 `eSrvChg`(固定键,PlugNotice)。
100    ///
101    /// ⚠ 纪律(DV4 教训):**先换插件 services() 当前返回,再调用本方法** ——
102    /// 宿主细节是现场取的,只申报不改内容会造成索引与 live 细节脱节。
103    ///
104    /// (0.2.0:Rust 无运行期代码热换;「更新」的运行期形态 = 目录随配置/状态改版。)
105    pub fn publish_services(&self, list: Vec<ServiceDesc>) {
106        let name = self.name.clone();
107        let version = self.registry.publish(&name, list);
108        let _ = self
109            .event
110            .put(Event::with_data(format!("{EVENT_SRV_CHG_PREFIX}{name}"), Arc::new(version.clone())));
111        let _ = self
112            .event
113            .put(Event::with_data(EVENT_SRV_CHG, Arc::new(crate::service::PlugNotice { name, version })));
114    }
115
116    // ================ 请求应答 ================
117
118    /// 请求出口:eReq.<target> + Envelope + std mpsc 一次性信道。
119    ///
120    /// **禁止自呼**:ask 指向自身 target 会占满自己的 worker 直到超时
121    /// (自己阻塞等自己的回包)——需要自身逻辑请直调。
122    ///
123    /// 时序:预检目标 Running → put → recv_timeout。
124    /// - 预检失败(不存在/未 Running/已 Quarantined)→ 立即 `Err(TargetGone)`;
125    /// - 回包 `Ok(Res)` 且契约类型匹配 → `Ok(Res)`;
126    /// - 回包 `Err(InvalidPayload)` **或** 回包类型与本侧契约不一致 → `Err(InvalidPayload)`;
127    /// - 信道断连(handler panic/信封丢失/目标邮箱溢出被丢)→ `Err(TargetGone)`(尽快,不虚耗超时);
128    /// - 等满时限 → `Err(Timeout)`;
129    /// - put 失败(总线已停)→ `Err(BusStopped)`。
130    pub fn ask<Req, Res>(&self, target: &str, req: Req, timeout: Duration) -> Result<Res, AskError>
131    where
132        Req: Any + Send + Sync,
133        Res: Any + Send + Sync,
134    {
135        match self.registry.get(target) {
136            Some(entry) if entry.state.get() == PluginState::Running => {}
137            _ => return Err(AskError::TargetGone { target: target.to_string() }),
138        }
139        self.deliver(target, req, timeout)
140    }
141
142    /// 按服务 id 的请求出口(0.2.0):index 命中 → 现场类型闸门 → 发 eReq。
143    ///
144    /// - 无人提供该服务 → 立即 `Err(UnknownService)`(零成本显错);
145    /// - 有提供方但全都非 Running → 立即 `Err(TargetGone)`;
146    /// - Req 类型与服务声明的 req_type 不符 → 立即 `Err(InvalidPayload)`
147    ///   (把「绕一圈才发现错型」提前到发出之前);
148    /// - 多提供方 → 取注册序第一个 Running 者;后续 failover 由发起方在收不到回包后自定。
149    ///   其余失败面与 [`ask`](Self::ask) 完全一致。
150    pub fn ask_service<Req, Res>(&self, svc: &str, req: Req, timeout: Duration) -> Result<Res, AskError>
151    where
152        Req: Any + Send + Sync,
153        Res: Any + Send + Sync,
154    {
155        let providers = self.find_service(svc);
156        if providers.is_empty() {
157            return Err(AskError::UnknownService { service: svc.to_string() });
158        }
159        let Some(slot) = providers.iter().find(|p| p.state == PluginState::Running) else {
160            return Err(AskError::TargetGone { target: providers[0].name.clone() });
161        };
162        if slot.service.req_type != type_name::<Req>() {
163            return Err(AskError::InvalidPayload { target: slot.name.clone() });
164        }
165        self.deliver(&slot.name.clone(), req, timeout)
166    }
167
168    /// ask/ask_service 共用的投递段(Envelope + eReq + recv_timeout + 回包裁决)。
169    fn deliver<Req, Res>(&self, target: &str, req: Req, timeout: Duration) -> Result<Res, AskError>
170    where
171        Req: Any + Send + Sync,
172        Res: Any + Send + Sync,
173    {
174        let (envelope, reply_rx) = Envelope::new(Arc::new(req));
175        let put = self.event.put(Event::with_data(e_req_type(target), Arc::new(envelope)));
176        if put.is_err() {
177            return Err(AskError::BusStopped);
178        }
179        let boxed = reply_rx.recv_timeout(timeout).map_err(|e| match e {
180            OneshotErr::Timeout => AskError::Timeout { target: target.to_string() },
181            OneshotErr::Closed => AskError::TargetGone { target: target.to_string() },
182        })?;
183        // 回包为 Box<dyn Any>:downcast 到本侧契约 Result<Res, ReplyErr>
184        match boxed.downcast::<Result<Res, ReplyErr>>() {
185            Ok(inner) => match *inner {
186                Ok(res) => Ok(res),
187                Err(_) => Err(AskError::InvalidPayload { target: target.to_string() }),
188            },
189            // 回包类型与本侧契约不同(双方契约错配)→ 协议违约
190            Err(_) => Err(AskError::InvalidPayload { target: target.to_string() }),
191        }
192    }
193}