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 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 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}