1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright 2015-2019 Capital One Services, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::capability::Capability;
use crate::dispatch::WasccNativeDispatcher;
use crate::errors::{self, ErrorKind};
use crate::host::Invocation;
use crate::host::InvocationResponse;
use crate::Result;
use std::collections::HashMap;
use std::sync::RwLock;

lazy_static! {
    pub(crate) static ref PLUGMAN: RwLock<PluginManager> = { RwLock::new(PluginManager::new()) };
}

#[derive(Default)]
pub(crate) struct PluginManager {
    plugins: HashMap<String, Capability>, //plugins: HashMap<String, Box<dyn CapabilityProvider>>,
                                          //loaded_libraries: HashMap<String, Library>
}

impl PluginManager {
    pub fn new() -> PluginManager {
        Self::default()
    }

    pub fn register_dispatcher(
        &mut self,
        capid: &str,
        dispatcher: WasccNativeDispatcher,
    ) -> Result<()> {
        match self.plugins.get(capid) {
            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> {
        let v: Vec<&str> = inv.operation.split('!').collect();
        let capability_id = v[0];
        match self.plugins.get(capability_id) {
            Some(c) => match c.plugin.handle_call(&inv.origin, &v[1], &inv.msg) {
                Ok(msg) => Ok(InvocationResponse::success(msg)),
                Err(e) => Err(errors::new(errors::ErrorKind::HostCallFailure(e))),
            },
            None => Err(errors::new(ErrorKind::CapabilityProvider(format!(
                "No such capability ID registered: {}",
                capability_id
            )))),
        }
    }

    pub fn add_plugin(&mut self, plugin: Capability) -> Result<()> {
        if self.plugins.contains_key(&plugin.capid) {
            Err(errors::new(errors::ErrorKind::CapabilityProvider(format!(
                "Duplicate capability ID attempted to register provider: {}",
                plugin.capid
            ))))
        } else {
            self.plugins.insert(plugin.capid.to_string(), plugin);
            Ok(())
        }
    }

    pub fn remove_plugin(&mut self, capid: &str) -> Result<()> {
        if let Some(plugin) = self.plugins.remove(capid) {
            drop(plugin);
        }
        Ok(())
    }
}