wascc-host 0.14.0

WebAssembly Secure Capabilities Connector (waSCC) Host Runtime
Documentation
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<RouteKey, NativeCapability>,
}

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<InvocationResponse> {
        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(())
    }
}