wascc_host/
plugins.rs

1use crate::capability::NativeCapability;
2use crate::dispatch::WasccNativeDispatcher;
3use crate::errors::{self, ErrorKind};
4use crate::inthost::Invocation;
5use crate::inthost::{InvocationResponse, WasccEntity};
6use crate::{Result, RouteKey};
7use std::collections::HashMap;
8
9#[derive(Default)]
10pub(crate) struct PluginManager {
11    plugins: HashMap<RouteKey, NativeCapability>,
12}
13
14impl PluginManager {
15    pub fn register_dispatcher(
16        &mut self,
17        binding: &str,
18        capid: &str,
19        dispatcher: WasccNativeDispatcher,
20    ) -> Result<()> {
21        let key = RouteKey::new(binding, capid);
22        match self.plugins.get(&key) {
23            Some(p) => match p.plugin.configure_dispatch(Box::new(dispatcher)) {
24                Ok(_) => Ok(()),
25                Err(_) => Err(errors::new(ErrorKind::CapabilityProvider(
26                    "Failed to configure dispatch on provider".into(),
27                ))),
28            },
29            None => Err(errors::new(ErrorKind::CapabilityProvider(
30                "Attempt to register dispatcher for non-existent plugin".into(),
31            ))),
32        }
33    }
34
35    pub fn call(&self, inv: &Invocation) -> Result<InvocationResponse> {
36        if let WasccEntity::Capability { capid, binding } = &inv.target {
37            let route_key = RouteKey::new(&binding, &capid);
38            let actor = if let WasccEntity::Actor(s) = &inv.origin {
39                s.to_string()
40            } else {
41                "SHOULD NEVER SEND CAP-ORIGIN INVOCATION TO ANOTHER CAP".to_string()
42            };
43            match self.plugins.get(&route_key) {
44                // native capability is registered via plugin
45                Some(c) => match c.plugin.handle_call(&actor, &inv.operation, &inv.msg) {
46                    Ok(msg) => Ok(InvocationResponse::success(inv, msg)),
47                    Err(e) => Err(errors::new(errors::ErrorKind::HostCallFailure(e))),
48                },
49                // if there's no plugin, return an error
50                None => Err(errors::new(ErrorKind::CapabilityProvider(format!(
51                    "No such capability ID registered as native plug-in {:?}",
52                    route_key
53                )))),
54            }
55        } else {
56            Err(errors::new(ErrorKind::MiscHost(
57                "Attempted to invoke a capability provider plugin as though it were an actor. Bad route?".into()
58            )))
59        }
60    }
61
62    pub fn add_plugin(&mut self, plugin: NativeCapability) -> Result<()> {
63        let key = RouteKey::new(&plugin.binding_name, &plugin.id());
64        if self.plugins.contains_key(&key) {
65            Err(errors::new(errors::ErrorKind::CapabilityProvider(format!(
66                "Duplicate capability ID attempted to register provider: ({},{})",
67                plugin.binding_name,
68                plugin.id()
69            ))))
70        } else {
71            self.plugins.insert(key, plugin);
72            Ok(())
73        }
74    }
75
76    pub fn remove_plugin(&mut self, binding: &str, capid: &str) -> Result<()> {
77        let key = RouteKey::new(&binding, &capid);
78        if let Some(plugin) = self.plugins.remove(&key) {
79            drop(plugin);
80        }
81        Ok(())
82    }
83}