1use 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#[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 pub fn name(&self) -> &str {
36 &self.name
37 }
38
39 pub fn put(&self, event: Event) -> Result<(), PutError> {
41 self.event.put(event)
42 }
43
44 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 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 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 pub fn services_of(&self, name: &str) -> Option<Arc<Vec<ServiceDesc>>> {
76 self.registry.services_of(name)
77 }
78
79 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 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 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 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 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 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 Err(_) => Err(AskError::InvalidPayload { target: target.to_string() }),
191 }
192 }
193}