1use crate::context::PluginContext;
12use crate::error::PluginError;
13use crate::forwarder::{make_forwarder, Forwarder};
14use crate::log_plugin::{
15 LogData, EVENT_LOG, EVENT_PLUG_DOWN, EVENT_PLUG_DOWN_EVENT_PREFIX, EVENT_PLUG_UP,
16 EVENT_PLUG_UP_PREFIX, LOG_LEVEL_WARN,
17};
18use crate::plugin::{CLOSE_JOIN_TIMEOUT, Plugin, valid_plugin_name};
19use crate::registry::{EntryStats, PluginEntry, PluginStateCell, PluginStateCode, Registry};
20use crate::service::PlugNotice;
21use crate::worker::spawn_worker;
22use ek_event::{EventEngine, HandlerId};
23use std::any::Any;
24use std::sync::atomic::Ordering;
25use std::sync::{Arc, Mutex, RwLock};
26use std::time::{Duration, Instant};
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum PluginState {
31 Ready,
32 Running,
33 Stopping,
34 Exited,
35 Quarantined,
36}
37
38impl PluginState {
39 pub(crate) fn from_code(c: u8) -> Self {
40 match c {
41 0 => Self::Ready,
42 1 => Self::Running,
43 2 => Self::Stopping,
44 3 => Self::Exited,
45 _ => Self::Quarantined,
46 }
47 }
48 fn from_code_enum(code: PluginStateCode) -> Self {
49 Self::from_code(code as u8)
50 }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct PluginInfo {
56 pub name: String,
57 pub version: String,
59 pub state: PluginState,
60 pub deps: Vec<String>,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
65pub struct MailStats {
66 pub spilled: u64,
68 pub panics: u64,
70}
71
72fn log_event(source: &str, msg: String) -> ek_event::Event {
73 ek_event::Event::with_data(
74 EVENT_LOG,
75 Arc::new(LogData {
76 level: LOG_LEVEL_WARN,
77 source: source.to_string(),
78 msg,
79 }),
80 )
81}
82
83pub struct MainEngine {
84 event: Arc<EventEngine>,
85 registry: Arc<Registry>,
86 started_order: Mutex<Option<Vec<String>>>,
88 closed: RwLock<bool>,
89}
90
91impl MainEngine {
92 pub fn new(event: Option<Arc<EventEngine>>) -> Self {
94 Self {
95 event: event.unwrap_or_else(|| Arc::new(EventEngine::new())),
96 registry: Arc::new(Registry::new()),
97 started_order: Mutex::new(None),
98 closed: RwLock::new(false),
99 }
100 }
101
102 pub fn event_engine(&self) -> &Arc<EventEngine> {
104 &self.event
105 }
106
107 fn closed_check(&self) -> Result<(), PluginError> {
108 if *self.closed.read().unwrap() {
109 Err(PluginError::Stopped)
110 } else {
111 Ok(())
112 }
113 }
114
115 fn host_log(&self, msg: String) {
116 let _ = self.event.put(log_event("ek-core", msg));
117 }
118
119 pub fn add_plugin(&self, plugin: Arc<impl Plugin + 'static>) -> Result<(), PluginError> {
126 self.closed_check()?;
127 let name = plugin.name().to_string();
128 if !valid_plugin_name(&name) {
129 return Err(PluginError::IllegalName(name));
130 }
131 let deps: Vec<String> = plugin.deps().iter().map(|d| d.to_string()).collect();
132 if deps.iter().any(|d| d == &name) {
133 return Err(PluginError::DepCycle(vec![name]));
134 }
135 let mailbox_cap = plugin.mailbox_cap();
136 let any: Arc<dyn Any + Send + Sync> = Arc::clone(&plugin) as Arc<dyn Any + Send + Sync>;
137 let dyn_plugin: Arc<dyn Plugin> = plugin;
138 let svc_ids: Vec<String> = {
140 let mut ids = Vec::new();
141 for d in dyn_plugin.services() {
142 if !ids.contains(&d.id) {
143 ids.push(d.id);
144 }
145 }
146 ids
147 };
148
149 let mut w = self.registry.state_of.write().unwrap();
150 if w.entries.contains_key(&name) {
151 return Err(PluginError::Duplicate(name));
152 }
153 let entry = Arc::new(PluginEntry {
154 name: name.clone(),
155 plugin: dyn_plugin,
156 any,
157 state: PluginStateCell::new(PluginStateCode::Ready),
158 mailbox_cap,
159 deps,
160 mailbox: Mutex::new(None),
161 forwarder_ids: Mutex::new(Vec::new()),
162 worker: Mutex::new(None),
163 stats: Arc::new(EntryStats::default()),
164 });
165 w.order.push(entry.name.clone());
166 w.entries.insert(entry.name.clone(), entry);
167 drop(w);
168 self.registry.index_put(&name, &svc_ids);
169 self.registry.invalidate(&name);
170
171 let mut started = self.started_order.lock().unwrap();
173 if started.is_some() {
174 let entry = self.registry.get(&name).expect("just inserted");
175 self.launch_one(&entry);
176 started.as_mut().expect("checked Some").push(name);
177 }
178 Ok(())
179 }
180
181 pub fn get_state(&self, name: &str) -> Option<PluginState> {
183 self.registry.get(name).map(|e| e.state.get())
184 }
185
186 pub fn get_plugin(&self, name: &str) -> Option<PluginInfo> {
188 self.registry.info_of(name)
189 }
190
191 pub fn get_typed<T: Plugin + 'static>(&self, name: &str) -> Option<Arc<T>> {
193 let entry = self.registry.get(name)?;
194 Arc::downcast::<T>(Arc::clone(&entry.any)).ok()
195 }
196
197 pub fn plugin_names(&self) -> Vec<String> {
199 self.registry.names()
200 }
201
202 pub fn mail_stats(&self, name: &str) -> Option<MailStats> {
204 self.registry.get(name).map(|e| MailStats {
205 spilled: e.stats.spilled.load(Ordering::Acquire),
206 panics: e.stats.panics.load(Ordering::Acquire),
207 })
208 }
209
210 pub fn start(&self) -> Result<(), PluginError> {
215 let mut started = self.started_order.lock().unwrap();
216 if started.is_some() {
217 return Ok(());
218 }
219 self.closed_check()?;
220 self.event.start();
221 let order = self.registry.topo_order()?;
222 let mut launched = Vec::with_capacity(order.len());
223 for entry in order {
224 self.launch_one(&entry);
225 launched.push(entry.name.clone());
226 }
227 *started = Some(launched);
228 Ok(())
229 }
230
231 fn launch_one(&self, entry: &Arc<PluginEntry>) {
236 let ctx = Arc::new(PluginContext::new(
237 Arc::clone(&self.event),
238 Arc::clone(&self.registry),
239 entry.name.clone(),
240 ));
241 entry.plugin.on_init(&ctx);
242 let (tx, rx) = crossbeam_channel::bounded::<ek_event::Event>(entry.mailbox_cap);
243 *entry.mailbox.lock().unwrap() = Some(tx.clone());
244 let handler = spawn_worker(
245 Arc::clone(&entry.plugin),
246 rx,
247 entry.state.clone(),
248 Arc::clone(&entry.stats),
249 Arc::clone(&ctx),
250 Arc::clone(&self.event),
251 );
252 *entry.worker.lock().unwrap() = Some(handler);
253 let _ = entry.state.cas(PluginStateCode::Ready, PluginStateCode::Running);
255 let mut ids: Vec<HandlerId> = Vec::new();
256 for ty in entry.plugin.routes() {
257 let fwd = Forwarder::new(
258 tx.clone(),
259 Arc::clone(&entry.stats),
260 Arc::clone(&self.event),
261 entry.name.clone(),
262 );
263 let id = self.event.register(ty.into_owned(), make_forwarder(fwd));
264 ids.push(id);
265 }
266 *entry.forwarder_ids.lock().unwrap() = ids;
267 entry.plugin.on_start();
268
269 let version = entry.plugin.version().into_owned();
270 let _ = self.event.put(ek_event::Event::with_data(
271 format!("{EVENT_PLUG_UP_PREFIX}{}", entry.name),
272 Arc::new(version.clone()),
273 ));
274 let _ = self.event.put(ek_event::Event::with_data(
275 EVENT_PLUG_UP,
276 Arc::new(PlugNotice { name: entry.name.clone(), version }),
277 ));
278 }
279
280 fn close_one(&self, entry: &Arc<PluginEntry>, deadline: Instant) {
286 let pre_state = entry.state.get();
287 let call_stop = pre_state != PluginState::Ready;
288 let _ = entry.state.cas(PluginStateCode::Running, PluginStateCode::Stopping);
290 let ids: Vec<HandlerId> = std::mem::take(&mut *entry.forwarder_ids.lock().unwrap());
292 for id in ids {
293 self.event.unregister(id);
294 }
295 if call_stop {
297 entry.plugin.on_stop();
298 }
299 *entry.mailbox.lock().unwrap() = None;
301 while !entry.stats.done.load(Ordering::Acquire) && Instant::now() < deadline {
303 std::thread::sleep(Duration::from_millis(2));
304 }
305 if let Some(handle) = entry.worker.lock().unwrap().take() {
306 if entry.stats.done.load(Ordering::Acquire) {
307 let _ = handle.join();
308 } else {
309 self.host_log(format!(
310 "close timeout: worker of {:?} still busy; detach and keep draining",
311 entry.name
312 ));
313 }
314 }
315 let _ = entry.state.cas(PluginStateCode::Stopping, PluginStateCode::Exited);
317 }
318
319 pub fn close(&self, timeout: Duration) {
321 let order = self.started_order.lock().unwrap().take();
322 *self.closed.write().unwrap() = true;
323 let deadline = Instant::now() + timeout.max(Duration::from_millis(1));
324 if let Some(order) = order {
325 for name in order.iter().rev() {
326 if let Some(entry) = self.registry.get(name) {
327 self.close_one(&entry, deadline);
328 }
329 }
330 }
331 self.registry.clear();
332 }
333
334 pub fn close_all(&self, timeout: Duration) {
336 self.close(timeout);
337 self.event.stop();
338 }
339
340 pub fn remove_plugin(&self, name: &str) -> Result<(), PluginError> {
347 self.closed_check()?;
348 let entry = self
349 .registry
350 .get(name)
351 .ok_or_else(|| PluginError::UnknownName(name.to_string()))?;
352 let dependents = self.registry.any_depends_on(name);
353 if !dependents.is_empty() {
354 self.host_log(format!(
355 "remove_plugin {:?} still depended on by {:?}",
356 name, dependents
357 ));
358 }
359 let deadline = Instant::now() + CLOSE_JOIN_TIMEOUT;
360 if entry.state.get() == PluginState::from_code_enum(PluginStateCode::Running) {
361 self.close_one(&entry, deadline);
362 } else {
363 let ids: Vec<HandlerId> = std::mem::take(&mut *entry.forwarder_ids.lock().unwrap());
365 for id in ids {
366 self.event.unregister(id);
367 }
368 *entry.mailbox.lock().unwrap() = None;
369 }
370 let version = entry.plugin.version().into_owned();
371 self.registry
372 .remove(name)
373 .ok_or_else(|| PluginError::UnknownName(name.to_string()))?;
374 self.registry.index_remove(name);
376 self.registry.invalidate(name);
377 let _ = self.event.put(ek_event::Event::with_data(
378 format!("{EVENT_PLUG_DOWN_EVENT_PREFIX}{name}"),
379 Arc::new(version.clone()),
380 ));
381 let _ = self.event.put(ek_event::Event::with_data(
382 EVENT_PLUG_DOWN,
383 Arc::new(PlugNotice { name: name.to_string(), version }),
384 ));
385 Ok(())
386 }
387}