1mod dynamic_plugin;
14mod static_plugin;
15
16use zenoh_keyexpr::keyexpr;
17use zenoh_result::ZResult;
18use zenoh_util::LibLoader;
19
20use self::{
21 dynamic_plugin::{DynamicPlugin, DynamicPluginSource},
22 static_plugin::StaticPlugin,
23};
24use crate::*;
25
26pub trait DeclaredPlugin<StartArgs, Instance>: PluginStatus {
27 fn as_status(&self) -> &dyn PluginStatus;
28 fn load(&mut self) -> ZResult<Option<&mut dyn LoadedPlugin<StartArgs, Instance>>>;
29 fn loaded(&self) -> Option<&dyn LoadedPlugin<StartArgs, Instance>>;
30 fn loaded_mut(&mut self) -> Option<&mut dyn LoadedPlugin<StartArgs, Instance>>;
31}
32pub trait LoadedPlugin<StartArgs, Instance>: PluginStatus {
33 fn as_status(&self) -> &dyn PluginStatus;
34 fn required(&self) -> bool;
35 fn start(&mut self, args: &StartArgs) -> ZResult<&mut dyn StartedPlugin<StartArgs, Instance>>;
36 fn started(&self) -> Option<&dyn StartedPlugin<StartArgs, Instance>>;
37 fn started_mut(&mut self) -> Option<&mut dyn StartedPlugin<StartArgs, Instance>>;
38}
39
40pub trait StartedPlugin<StartArgs, Instance>: PluginStatus {
41 fn as_status(&self) -> &dyn PluginStatus;
42 fn stop(&mut self);
43 fn instance(&self) -> &Instance;
44 fn instance_mut(&mut self) -> &mut Instance;
45}
46
47struct PluginRecord<StartArgs: PluginStartArgs, Instance: PluginInstance>(
48 Box<dyn DeclaredPlugin<StartArgs, Instance> + Send + Sync>,
49);
50
51impl<StartArgs: PluginStartArgs, Instance: PluginInstance> PluginRecord<StartArgs, Instance> {
52 fn new<P: DeclaredPlugin<StartArgs, Instance> + Send + Sync + 'static>(plugin: P) -> Self {
53 Self(Box::new(plugin))
54 }
55}
56
57impl<StartArgs: PluginStartArgs, Instance: PluginInstance> PluginStatus
58 for PluginRecord<StartArgs, Instance>
59{
60 fn name(&self) -> &str {
61 self.0.name()
62 }
63
64 fn id(&self) -> &str {
65 self.0.id()
66 }
67
68 fn version(&self) -> Option<&str> {
69 self.0.version()
70 }
71 fn long_version(&self) -> Option<&str> {
72 self.0.long_version()
73 }
74 fn path(&self) -> &str {
75 self.0.path()
76 }
77 fn state(&self) -> PluginState {
78 self.0.state()
79 }
80 fn report(&self) -> PluginReport {
81 self.0.report()
82 }
83}
84
85impl<StartArgs: PluginStartArgs, Instance: PluginInstance> DeclaredPlugin<StartArgs, Instance>
86 for PluginRecord<StartArgs, Instance>
87{
88 fn as_status(&self) -> &dyn PluginStatus {
89 self
90 }
91 fn load(&mut self) -> ZResult<Option<&mut dyn LoadedPlugin<StartArgs, Instance>>> {
92 self.0.load()
93 }
94 fn loaded(&self) -> Option<&dyn LoadedPlugin<StartArgs, Instance>> {
95 self.0.loaded()
96 }
97 fn loaded_mut(&mut self) -> Option<&mut dyn LoadedPlugin<StartArgs, Instance>> {
98 self.0.loaded_mut()
99 }
100}
101
102pub struct PluginsManager<StartArgs: PluginStartArgs, Instance: PluginInstance> {
105 default_lib_prefix: String,
106 loader: Option<LibLoader>,
107 plugins: Vec<PluginRecord<StartArgs, Instance>>,
108}
109
110impl<StartArgs: PluginStartArgs + 'static, Instance: PluginInstance + 'static>
111 PluginsManager<StartArgs, Instance>
112{
113 pub fn dynamic<S: Into<String>>(loader: LibLoader, default_lib_prefix: S) -> Self {
115 PluginsManager {
116 default_lib_prefix: default_lib_prefix.into(),
117 loader: Some(loader),
118 plugins: Default::default(),
119 }
120 }
121 pub fn static_plugins_only() -> Self {
123 PluginsManager {
124 default_lib_prefix: String::new(),
125 loader: None,
126 plugins: Default::default(),
127 }
128 }
129
130 pub fn declare_static_plugin<
132 P: Plugin<StartArgs = StartArgs, Instance = Instance> + Send + Sync,
133 S: Into<String>,
134 >(
135 &mut self,
136 id: S,
137 required: bool,
138 ) {
139 let id = id.into();
140 let plugin_loader: StaticPlugin<StartArgs, Instance, P> =
141 StaticPlugin::new(id.clone(), required);
142
143 if self.get_plugin_index(&id).is_some() {
144 tracing::warn!(
145 "Duplicate plugin with ID: {id}, only the last declared one will be loaded"
146 )
147 }
148
149 self.plugins.push(PluginRecord::new(plugin_loader));
150 tracing::debug!(
151 "Declared static plugin Id:{} - Name:{}",
152 self.plugins.last().unwrap().id(),
153 self.plugins.last().unwrap().name()
154 );
155 }
156
157 pub fn declare_dynamic_plugin_by_name<S: Into<String>>(
159 &mut self,
160 id: S,
161 plugin_name: S,
162 required: bool,
163 ) -> ZResult<&mut dyn DeclaredPlugin<StartArgs, Instance>> {
164 let plugin_name = plugin_name.into();
165 let id = id.into();
166 let libplugin_name = format!("{}{}", self.default_lib_prefix, plugin_name);
167 let libloader = self
168 .loader
169 .as_ref()
170 .ok_or("Dynamic plugin loading is disabled")?
171 .clone();
172 tracing::debug!(
173 "Declared dynamic plugin {} by name {}",
174 &id,
175 &libplugin_name
176 );
177 let loader = DynamicPlugin::new(
178 plugin_name,
179 id.clone(),
180 DynamicPluginSource::ByName((libloader, libplugin_name)),
181 required,
182 );
183
184 if self.get_plugin_index(&id).is_some() {
185 tracing::warn!(
186 "Duplicate plugin with ID: {id}, only the last declared one will be loaded"
187 )
188 }
189 self.plugins.push(PluginRecord::new(loader));
190 Ok(self.plugins.last_mut().unwrap())
191 }
192
193 pub fn declare_dynamic_plugin_by_paths<S: Into<String>, P: AsRef<str> + std::fmt::Debug>(
195 &mut self,
196 name: S,
197 id: S,
198 paths: &[P],
199 required: bool,
200 ) -> ZResult<&mut dyn DeclaredPlugin<StartArgs, Instance>> {
201 let name = name.into();
202 let id = id.into();
203 let paths = paths.iter().map(|p| p.as_ref().into()).collect();
204 tracing::debug!("Declared dynamic plugin {} by paths {:?}", &id, &paths);
205 let loader = DynamicPlugin::new(
206 name,
207 id.clone(),
208 DynamicPluginSource::ByPaths(paths),
209 required,
210 );
211
212 if self.get_plugin_index(&id).is_some() {
213 tracing::warn!(
214 "Duplicate plugin with ID: {id}, only the last declared one will be loaded"
215 )
216 }
217
218 self.plugins.push(PluginRecord::new(loader));
219 Ok(self.plugins.last_mut().unwrap())
220 }
221
222 fn get_plugin_index(&self, id: &str) -> Option<usize> {
223 self.plugins.iter().position(|p| p.id() == id)
224 }
225
226 pub fn declared_plugins_iter(
228 &self,
229 ) -> impl Iterator<Item = &dyn DeclaredPlugin<StartArgs, Instance>> + '_ {
230 self.plugins
231 .iter()
232 .map(|p| p as &dyn DeclaredPlugin<StartArgs, Instance>)
233 }
234
235 pub fn declared_plugins_iter_mut(
237 &mut self,
238 ) -> impl Iterator<Item = &mut dyn DeclaredPlugin<StartArgs, Instance>> + '_ {
239 self.plugins
240 .iter_mut()
241 .map(|p| p as &mut dyn DeclaredPlugin<StartArgs, Instance>)
242 }
243
244 pub fn loaded_plugins_iter(
246 &self,
247 ) -> impl Iterator<Item = &dyn LoadedPlugin<StartArgs, Instance>> + '_ {
248 self.declared_plugins_iter().filter_map(|p| p.loaded())
249 }
250
251 pub fn loaded_plugins_iter_mut(
253 &mut self,
254 ) -> impl Iterator<Item = &mut dyn LoadedPlugin<StartArgs, Instance>> + '_ {
255 self.declared_plugins_iter_mut()
256 .filter_map(|p| p.loaded_mut())
257 }
258
259 pub fn started_plugins_iter(
261 &self,
262 ) -> impl Iterator<Item = &dyn StartedPlugin<StartArgs, Instance>> + '_ {
263 self.loaded_plugins_iter().filter_map(|p| p.started())
264 }
265
266 pub fn started_plugins_iter_mut(
268 &mut self,
269 ) -> impl Iterator<Item = &mut dyn StartedPlugin<StartArgs, Instance>> + '_ {
270 self.loaded_plugins_iter_mut()
271 .filter_map(|p| p.started_mut())
272 }
273
274 pub fn plugin(&self, id: &str) -> Option<&dyn DeclaredPlugin<StartArgs, Instance>> {
276 let index = self.get_plugin_index(id)?;
277 Some(&self.plugins[index])
278 }
279
280 pub fn plugin_mut(&mut self, id: &str) -> Option<&mut dyn DeclaredPlugin<StartArgs, Instance>> {
282 let index = self.get_plugin_index(id)?;
283 Some(&mut self.plugins[index])
284 }
285
286 pub fn loaded_plugin(&self, id: &str) -> Option<&dyn LoadedPlugin<StartArgs, Instance>> {
288 self.plugin(id)?.loaded()
289 }
290
291 pub fn loaded_plugin_mut(
293 &mut self,
294 id: &str,
295 ) -> Option<&mut dyn LoadedPlugin<StartArgs, Instance>> {
296 self.plugin_mut(id)?.loaded_mut()
297 }
298
299 pub fn started_plugin(&self, id: &str) -> Option<&dyn StartedPlugin<StartArgs, Instance>> {
301 self.loaded_plugin(id)?.started()
302 }
303
304 pub fn started_plugin_mut(
306 &mut self,
307 id: &str,
308 ) -> Option<&mut dyn StartedPlugin<StartArgs, Instance>> {
309 self.loaded_plugin_mut(id)?.started_mut()
310 }
311}
312
313impl<StartArgs: PluginStartArgs + 'static, Instance: PluginInstance + 'static> PluginControl
314 for PluginsManager<StartArgs, Instance>
315{
316 fn plugins_status(&self, names: &keyexpr) -> Vec<PluginStatusRec<'_>> {
317 tracing::debug!(
318 "Plugin manager with prefix `{}` : requested plugins_status {:?}",
319 self.default_lib_prefix,
320 names
321 );
322 let mut plugins = Vec::new();
323 for plugin in self.declared_plugins_iter() {
324 let id = unsafe { keyexpr::from_str_unchecked(plugin.id()) };
325 if names.includes(id) {
326 let status = PluginStatusRec::new(plugin.as_status());
327 plugins.push(status);
328 }
329 if let Some(plugin) = plugin.loaded() {
331 if let Some(plugin) = plugin.started() {
332 if let [names, ..] = names.strip_prefix(id)[..] {
333 plugins.append(
334 &mut plugin
335 .instance()
336 .plugins_status(names)
337 .into_iter()
338 .map(|s| s.prepend_name(id))
339 .collect(),
340 );
341 }
342 }
343 }
344 }
345 plugins
346 }
347}