1use crate::envelope::{Envelope, OneshotErr, ReplyErr, e_req_type, e_to_type};
13use crate::error::AskError;
14use crate::lifecycle::{EVENT_SRV_CHG, EVENT_SRV_CHG_PREFIX};
15use crate::main_engine::{PluginInfo, PluginState};
16use crate::registry::Registry;
17use crate::service::{ProviderRef, ServiceDesc};
18use ek_event::{Event, EventEngine, PutError};
19use std::any::{Any, type_name};
20use std::sync::Arc;
21use std::time::Duration;
22
23#[derive(Clone)]
25pub struct PluginContext {
26 pub(crate) event: Arc<EventEngine>,
27 pub(crate) registry: Arc<Registry>,
28 pub(crate) name: String,
29}
30
31impl PluginContext {
32 pub(crate) fn new(event: Arc<EventEngine>, registry: Arc<Registry>, name: String) -> Self {
33 Self {
34 event,
35 registry,
36 name,
37 }
38 }
39
40 pub fn name(&self) -> &str {
42 &self.name
43 }
44
45 pub fn put(&self, event: Event) -> Result<(), PutError> {
50 self.event.put(event)
51 }
52
53 pub fn notify(&self, target: &str, payload: Arc<dyn Any + Send + Sync>) {
55 let _ = self.event.put(Event::with_data(e_to_type(target), payload));
56 }
57
58 pub fn plugins(&self) -> Vec<PluginInfo> {
62 let mut out = Vec::new();
63 for name in self.registry.names() {
64 if let Some(info) = self.registry.info_of(&name) {
65 out.push(info);
66 }
67 }
68 out
69 }
70
71 pub fn services_of(&self, name: &str) -> Option<Arc<Vec<ServiceDesc>>> {
75 self.registry.services_of(name)
76 }
77
78 pub fn find_service(&self, svc: &str) -> Vec<ProviderRef> {
81 let mut out = Vec::new();
82 for name in self.registry.index_providers(svc) {
83 let Some(list) = self.registry.services_of(&name) else {
84 continue;
85 };
86 let Some(entry) = self.registry.get(&name) else {
87 continue;
88 };
89 if let Some(desc) = list.iter().find(|d| d.id == svc) {
90 out.push(ProviderRef {
91 name: entry.name.clone(),
92 version: entry.plugin.version().into_owned(),
93 state: entry.state.get(),
94 service: desc.clone(),
95 });
96 }
97 }
98 out
99 }
100
101 pub fn publish_services(&self, list: Vec<ServiceDesc>) {
109 let name = self.name.clone();
110 let version = self.registry.publish(&name, list);
111 let _ = self.event.put(Event::with_data(
112 format!("{EVENT_SRV_CHG_PREFIX}{name}"),
113 Arc::new(version.clone()),
114 ));
115 let _ = self.event.put(Event::with_data(
116 EVENT_SRV_CHG,
117 Arc::new(crate::service::PlugNotice { name, version }),
118 ));
119 }
120
121 pub fn ask<Req, Res>(&self, target: &str, req: Req, timeout: Duration) -> Result<Res, AskError>
136 where
137 Req: Any + Send + Sync,
138 Res: Any + Send + Sync,
139 {
140 match self.registry.get(target) {
141 Some(entry) if entry.state.get() == PluginState::Running => {}
142 _ => {
143 return Err(AskError::TargetGone {
144 target: target.to_string(),
145 });
146 }
147 }
148 self.deliver(target, req, timeout)
149 }
150
151 pub fn ask_service<Req, Res>(
160 &self,
161 svc: &str,
162 req: Req,
163 timeout: Duration,
164 ) -> Result<Res, AskError>
165 where
166 Req: Any + Send + Sync,
167 Res: Any + Send + Sync,
168 {
169 let providers = self.find_service(svc);
170 if providers.is_empty() {
171 return Err(AskError::UnknownService {
172 service: svc.to_string(),
173 });
174 }
175 let Some(slot) = providers.iter().find(|p| p.state == PluginState::Running) else {
176 return Err(AskError::TargetGone {
177 target: providers[0].name.clone(),
178 });
179 };
180 if slot.service.req_type != type_name::<Req>() {
181 return Err(AskError::InvalidPayload {
182 target: slot.name.clone(),
183 });
184 }
185 self.deliver(&slot.name.clone(), req, timeout)
186 }
187
188 fn deliver<Req, Res>(&self, target: &str, req: Req, timeout: Duration) -> Result<Res, AskError>
190 where
191 Req: Any + Send + Sync,
192 Res: Any + Send + Sync,
193 {
194 let (envelope, reply_rx) = Envelope::new(Arc::new(req));
195 let put = self
196 .event
197 .put(Event::with_data(e_req_type(target), Arc::new(envelope)));
198 if put.is_err() {
199 return Err(AskError::BusStopped);
200 }
201 let boxed = reply_rx.recv_timeout(timeout).map_err(|e| match e {
202 OneshotErr::Timeout => AskError::Timeout {
203 target: target.to_string(),
204 pending: self
206 .registry
207 .get(target)
208 .map(|e| e.stats.pending.load(std::sync::atomic::Ordering::Acquire))
209 .unwrap_or(0),
210 },
211 OneshotErr::Closed => AskError::TargetGone {
212 target: target.to_string(),
213 },
214 })?;
215 match boxed.downcast::<Result<Res, ReplyErr>>() {
217 Ok(inner) => match *inner {
218 Ok(res) => Ok(res),
219 Err(_) => Err(AskError::InvalidPayload {
220 target: target.to_string(),
221 }),
222 },
223 Err(_) => Err(AskError::InvalidPayload {
225 target: target.to_string(),
226 }),
227 }
228 }
229}