diff --git a/plugins/zenoh-plugin-trait/src/loading.rs b/plugins/zenoh-plugin-trait/src/loading.rs index 155045e13a..45fe71d8d5 100644 --- a/plugins/zenoh-plugin-trait/src/loading.rs +++ b/plugins/zenoh-plugin-trait/src/loading.rs @@ -18,27 +18,13 @@ use vtable::{Compatibility, PluginLoaderVersion, PluginVTable, PLUGIN_LOADER_VER use zenoh_result::{bail, ZResult}; use zenoh_util::LibLoader; -struct PluginInstance { +pub struct PluginRecord { starter: Box + Send + Sync>, running_plugin: Option, } -impl PluginInfo - for PluginInstance -{ - fn name(&self) -> &str { - self.starter.name() - } - fn path(&self) -> &str { - self.starter.path() - } - fn deletable(&self) -> bool { - self.starter.deletable() - } -} - impl - PluginInstance + PluginRecord { fn new + Send + Sync + 'static>(starter: T) -> Self { Self { @@ -46,66 +32,82 @@ impl running_plugin: None, } } - fn get_running_plugin(&self) -> Option<&RunningPlugin> { - self.running_plugin.as_ref() - } - fn stop(&mut self) -> bool { + pub fn running(&self) -> Option<&dyn RunningPluginRecord> { if self.running_plugin.is_some() { - self.running_plugin = None; - true + Some(self) } else { - false + None } } - fn start(&mut self, args: &StartArgs) -> ZResult { + pub fn running_mut( + &mut self, + ) -> Option<&mut dyn RunningPluginRecord> { if self.running_plugin.is_some() { - return Ok(false); + Some(self) + } else { + None } - let plugin = self.starter.start(args)?; - self.running_plugin = Some(plugin); - Ok(true) } - fn as_plugin_info(&self) -> &dyn PluginInfo { - self + pub fn start( + &mut self, + args: &StartArgs, + ) -> ZResult<(bool, &mut dyn RunningPluginRecord)> { + let already_running = self.running_plugin.is_some(); + if !already_running { + self.running_plugin = Some(self.starter.start(args)?); + } + Ok((already_running, self)) + } + pub fn name(&self) -> &str { + self.starter.name() + } + pub fn path(&self) -> &str { + self.starter.path() + } + pub fn deletable(&self) -> bool { + self.starter.deletable() } } -/// A plugins manager that handles starting and stopping plugins. -/// Plugins can be loaded from shared libraries using [`Self::load_plugin_by_name`] or [`Self::load_plugin_by_paths`], or added directly from the binary if available using [`Self::add_static`]. -pub struct PluginsManager { - default_lib_prefix: String, - loader: Option, - plugins: Vec>, -} - -/// Unique identifier of plugin in plugin manager. Actually is just an index in the plugins list. -/// It's guaranteed that if intex is obtained from plugin manager, it's valid for this plugin manager. -/// (at least at this moment, when there is no pluing unload support). -/// Using it instead of plugin name allows to avoid checking for ``Option`` every time. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct PluginIndex(usize); - -/// Unique identifier of running plugin in plugin manager. -/// The ``RunningPligin`` insterface can be accessed through this index without -/// additional checks. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct RunningPluginIndex(PluginIndex); - -/// Trait allowing to use ``RunningPluginIndex`` as ``PluginIndex`` -pub trait PluginIndexTrait { - fn index(&self) -> PluginIndex; +pub trait RunningPluginRecord +{ + fn name(&self) -> &str; + fn path(&self) -> &str; + fn deletable(&self) -> bool; + fn stop(&mut self); + fn running(&self) -> &RunningPlugin; + fn running_mut(&mut self) -> &mut RunningPlugin; } -impl PluginIndexTrait for PluginIndex { - fn index(&self) -> PluginIndex { - *self +impl + RunningPluginRecord for PluginRecord +{ + fn name(&self) -> &str { + self.name() + } + fn path(&self) -> &str { + self.path() + } + fn deletable(&self) -> bool { + self.deletable() + } + fn stop(&mut self) { + self.running_plugin = None; + } + fn running(&self) -> &RunningPligin { + self.running_plugin.as_ref().unwrap() + } + fn running_mut(&mut self) -> &mut RunningPligin { + self.running_plugin.as_mut().unwrap() } } -impl PluginIndexTrait for RunningPluginIndex { - fn index(&self) -> PluginIndex { - self.0 - } +/// A plugins manager that handles starting and stopping plugins. +/// Plugins can be loaded from shared libraries using [`Self::load_plugin_by_name`] or [`Self::load_plugin_by_paths`], or added directly from the binary if available using [`Self::add_static`]. +pub struct PluginsManager { + default_lib_prefix: String, + loader: Option, + plugins: Vec>, } impl @@ -135,86 +137,81 @@ impl Self { let plugin_starter: StaticPlugin

= StaticPlugin::new(); - self.plugins.push(PluginInstance::new(plugin_starter)); + self.plugins.push(PluginRecord::new(plugin_starter)); self } - /// Returns `true` if the plugin with the given index exists in the manager. - pub fn check_plugin_index(&self, index: T) -> bool { - index.index().0 < self.plugins.len() - } - /// Returns plugin index by name - pub fn get_plugin_index(&self, name: &str) -> Option { - self.plugins - .iter() - .position(|p| p.name() == name) - .map(PluginIndex) + fn get_plugin_index(&self, name: &str) -> Option { + self.plugins.iter().position(|p| p.name() == name) } /// Returns plugin index by name or error if plugin not found - pub fn get_plugin_index_err(&self, name: &str) -> ZResult { + fn get_plugin_index_err(&self, name: &str) -> ZResult { self.get_plugin_index(name) .ok_or_else(|| format!("Plugin `{}` not found", name).into()) } - /// Returns running plugin index by name - pub fn get_running_plugin_index(&self, name: &str) -> Option { - self.get_plugin_index(name).and_then(|i| { - self.plugins[i.0] - .get_running_plugin() - .map(|_| RunningPluginIndex(i)) - }) + /// Lists the loaded plugins + pub fn plugins(&self) -> impl Iterator> + '_ { + self.plugins.iter() } - /// Returns running plugin index by name or error if plugin not found - pub fn get_running_plugin_index_err(&self, name: &str) -> ZResult { - self.get_running_plugin_index(name) - .ok_or_else(|| format!("Plugin `{}` not running", name).into()) + /// Lists the loaded plugins mutable + pub fn plugins_mut( + &mut self, + ) -> impl Iterator> + '_ { + self.plugins.iter_mut() } - /// Starts plugin. - /// Returns - /// Ok(true, index) => plugin was successfully started - /// Ok(false, index) => plugin was already running - /// Err(e) => starting the plugin failed due to `e` - pub fn start( - &mut self, - index: T, - args: &StartArgs, - ) -> ZResult<(bool, RunningPluginIndex)> { - let instance = &mut self.plugins[index.index().0]; - let already_started = instance.start(args)?; - Ok((already_started, RunningPluginIndex(index.index()))) + /// Lists the running plugins + pub fn running_plugins( + &self, + ) -> impl Iterator> + '_ { + self.plugins().filter_map(|p| p.running()) } - /// Stops `plugin`, returning `true` if it was indeed running. - pub fn stop(&mut self, index: RunningPluginIndex) -> ZResult { - let instance = &mut self.plugins[index.index().0]; - let was_running = instance.stop(); - Ok(was_running) + /// Lists the running plugins mutable + pub fn running_plugins_mut( + &mut self, + ) -> impl Iterator> + '_ { + self.plugins_mut().filter_map(|p| p.running_mut()) } - /// Lists the loaded plugins - pub fn plugins(&self) -> impl Iterator + '_ { - self.plugins.iter().enumerate().map(|(i, _)| PluginIndex(i)) + + /// Returns plugin record + pub fn plugin(&self, name: &str) -> ZResult<&PluginRecord> { + Ok(&self.plugins[self.get_plugin_index_err(name)?]) } - /// Lists the loaded plugins - pub fn running_plugins(&self) -> impl Iterator + '_ { - self.plugins.iter().enumerate().filter_map(|(i, p)| { - if p.get_running_plugin().is_some() { - Some(RunningPluginIndex(PluginIndex(i))) - } else { - None - } - }) + + /// Returns mutable plugin record + pub fn plugin_mut( + &mut self, + name: &str, + ) -> ZResult<&mut PluginRecord> { + let index = self.get_plugin_index_err(name)?; + Ok(&mut self.plugins[index]) } - /// Returns running plugin interface of plugin or none if plugin is stopped - pub fn running_plugin(&self, index: RunningPluginIndex) -> &RunningPlugin { - self.plugins[index.index().0].get_running_plugin().unwrap() + + /// Returns running plugin record + pub fn running_plugin( + &self, + name: &str, + ) -> ZResult<&dyn RunningPluginRecord> { + Ok(self + .plugin(name)? + .running() + .ok_or_else(|| format!("Plugin `{}` is not running", name))?) } - /// Returns plugin information - pub fn plugin(&self, index: T) -> &dyn PluginInfo { - self.plugins[index.index().0].as_plugin_info() + + /// Returns mutable running plugin record + pub fn running_plugin_mut( + &mut self, + name: &str, + ) -> ZResult<&mut dyn RunningPluginRecord> { + Ok(self + .plugin_mut(name)? + .running_mut() + .ok_or_else(|| format!("Plugin `{}` is not running", name))?) } fn load_plugin( @@ -231,7 +228,7 @@ impl ZResult { + ) -> ZResult<&mut PluginRecord> { let name = name.as_ref(); if self.get_plugin_index(name).is_some() { bail!("Plugin `{}` already loaded", name); @@ -245,15 +242,15 @@ impl p, Err(e) => bail!("After loading `{:?}`: {}", &p, e), }; - self.plugins.push(PluginInstance::new(plugin)); - Ok(PluginIndex(self.plugins.len() - 1)) + self.plugins.push(PluginRecord::new(plugin)); + Ok(self.plugins.last_mut().unwrap()) } /// Tries to load a plugin from the list of path to plugin (absolute or relative to the current working directory) pub fn load_plugin_by_paths, P: AsRef + std::fmt::Debug>( &mut self, name: T, paths: &[P], - ) -> ZResult { + ) -> ZResult<&mut PluginRecord> { let name = name.as_ref(); if self.get_plugin_index(name).is_some() { bail!("Plugin `{}` already loaded", name); @@ -263,8 +260,8 @@ impl { let plugin = Self::load_plugin(name, lib, p)?; - self.plugins.push(PluginInstance::new(plugin)); - return Ok(PluginIndex(self.plugins.len() - 1)); + self.plugins.push(PluginRecord::new(plugin)); + return Ok(self.plugins.last_mut().unwrap()); } Err(e) => log::warn!("Plugin '{}' load fail at {}: {}", &name, path, e), } diff --git a/zenoh/src/net/runtime/adminspace.rs b/zenoh/src/net/runtime/adminspace.rs index 6f09c98d7c..4753edd56b 100644 --- a/zenoh/src/net/runtime/adminspace.rs +++ b/zenoh/src/net/runtime/adminspace.rs @@ -73,10 +73,8 @@ impl ConfigValidator for AdminSpace { new: &serde_json::Map, ) -> ZResult>> { let plugins_mgr = zlock!(self.context.plugins_mgr); - let index = plugins_mgr.get_running_plugin_index_err(name)?; - plugins_mgr - .running_plugin(index) - .config_checker(path, current, new) + let plugin = plugins_mgr.running_plugin(name)?; + plugin.running().config_checker(path, current, new) } } @@ -125,10 +123,7 @@ impl AdminSpace { let mut active_plugins = plugins_mgr .running_plugins() - .map(|index| { - let info = plugins_mgr.plugin(index); - (info.name().to_string(), info.path().to_string()) - }) + .map(|rec| (rec.name().to_string(), rec.path().to_string())) .collect::>(); let context = Arc::new(AdminContext { @@ -193,28 +188,32 @@ impl AdminSpace { match diff { PluginDiff::Delete(name) => { active_plugins.remove(name.as_str()); - if let Some(index) = plugins_mgr.get_running_plugin_index(&name) { - let _ = plugins_mgr.stop(index); + if let Ok(running) = plugins_mgr.running_plugin_mut(&name) { + running.stop() } } PluginDiff::Start(plugin) => { let name = &plugin.name; - let index = if let Some(paths) = &plugin.paths { + let rec = if let Some(paths) = &plugin.paths { plugins_mgr.load_plugin_by_paths(name, paths) } else { plugins_mgr.load_plugin_by_backend_name(name, &plugin.name) }; - match index { - Ok(index) => { - let path = plugins_mgr.plugin(index).path().to_string(); - log::info!("Loaded plugin `{}` from {}", name, path); - match plugins_mgr.start(index, &admin.context.runtime) { - Ok((true, _)) => { - active_plugins.insert(name.into(), path.clone()); + match rec { + Ok(rec) => { + log::info!( + "Loaded plugin `{}` from {}", + rec.name(), + rec.path() + ); + match rec.start(&admin.context.runtime) { + Ok((true, rec)) => { + active_plugins + .insert(name.into(), rec.path().to_string()); log::info!( "Successfully started plugin `{}` from {}", - name, - path + rec.name(), + rec.path() ); } Ok((false, _)) => { @@ -437,8 +436,7 @@ fn router_data(context: &AdminContext, query: Query) { let plugins_mgr = zlock!(context.plugins_mgr); plugins_mgr .running_plugins() - .map(|index| plugins_mgr.plugin(index)) - .map(|info| (info.name(), json!({ "path": info.path() }))) + .map(|rec| (rec.name(), json!({ "path": rec.path() }))) .collect() }; diff --git a/zenohd/src/main.rs b/zenohd/src/main.rs index aadab85552..89540b4199 100644 --- a/zenohd/src/main.rs +++ b/zenohd/src/main.rs @@ -112,6 +112,17 @@ clap::Arg::new("adminspace-permissions").long("adminspace-permissions").value_na } }; + // for index in plugins.plugins() { + // let info = plugins[index].info(); + // let required = required_plugins.contains(name); + // log::info!( + // "Starting {req} plugin \"{name}\"", + // req = if required { "required" } else { "" } + // ); + + // let index = plugins.start(index, &runtime); + // } + for (name, path, start_result) in plugins.start_all(&runtime) { let required = required_plugins.contains(name); log::info!(