use crate::capability::NativeCapability; use crate::dispatch::WasccNativeDispatcher; use crate::errors::{self, ErrorKind}; use crate::inthost::Invocation; use crate::inthost::{InvocationResponse, WasccEntity}; use crate::{Result, RouteKey}; use std::collections::HashMap; #[derive(Default)] pub(crate) struct PluginManager { plugins: HashMap, } impl PluginManager { pub fn register_dispatcher( &mut self, binding: &str, capid: &str, dispatcher: WasccNativeDispatcher, ) -> Result<()> { let key = RouteKey::new(binding, capid); match self.plugins.get(&key) { Some(p) => match p.plugin.configure_dispatch(Box::new(dispatcher)) { Ok(_) => Ok(()), Err(_) => Err(errors::new(ErrorKind::CapabilityProvider( "Failed to configure dispatch on provider".into(), ))), }, None => Err(errors::new(ErrorKind::CapabilityProvider( "Attempt to register dispatcher for non-existent plugin".into(), ))), } } pub fn call(&self, inv: &Invocation) -> Result { if let WasccEntity::Capability { capid, binding } = &inv.target { let route_key = RouteKey::new(&binding, &capid); let actor = if let WasccEntity::Actor(s) = &inv.origin { s.to_string() } else { "SHOULD NEVER SEND CAP-ORIGIN INVOCATION TO ANOTHER CAP".to_string() }; match self.plugins.get(&route_key) { // native capability is registered via plugin Some(c) => match c.plugin.handle_call(&actor, &inv.operation, &inv.msg) { Ok(msg) => Ok(InvocationResponse::success(inv, msg)), Err(e) => Err(errors::new(errors::ErrorKind::HostCallFailure(e))), }, // if there's no plugin, return an error None => Err(errors::new(ErrorKind::CapabilityProvider(format!( "No such capability ID registered as native plug-in {:?}", route_key )))), } } else { Err(errors::new(ErrorKind::MiscHost( "Attempted to invoke a capability provider plugin as though it were an actor. Bad route?".into() ))) } } pub fn add_plugin(&mut self, plugin: NativeCapability) -> Result<()> { let key = RouteKey::new(&plugin.binding_name, &plugin.id()); if self.plugins.contains_key(&key) { Err(errors::new(errors::ErrorKind::CapabilityProvider(format!( "Duplicate capability ID attempted to register provider: ({},{})", plugin.binding_name, plugin.id() )))) } else { self.plugins.insert(key, plugin); Ok(()) } } pub fn remove_plugin(&mut self, binding: &str, capid: &str) -> Result<()> { let key = RouteKey::new(&binding, &capid); if let Some(plugin) = self.plugins.remove(&key) { drop(plugin); } Ok(()) } }