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
// Copyright 2015-2018 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.

//! # Traits used for capabilities and capability providers
//! 
//! 

use std::any::Any;
use std::error::Error;

/// The dispatcher is used by a capability provider to send commands to a guest module, expecting
/// an event in return
pub trait Dispatcher: Any + Send + Sync {
    fn dispatch(&self, op: &str, msg: &[u8]) -> Result<Vec<u8>, Box<dyn Error>>;
}

/// The NullDispatcher is as its name implies--a dispatcher that does nothing. This is convenient for
/// initializing a capability provider with a null dispatcher, and then swapping it for a real dispatcher
/// when the host runtime provides one tethered with the appropriate channels
#[derive(Default)]
pub struct NullDispatcher {}

impl NullDispatcher {
    pub fn new() -> NullDispatcher {
        NullDispatcher {}
    }
}

impl Dispatcher for NullDispatcher {
    fn dispatch(&self, _op: &str, _msg: &[u8]) -> Result<Vec<u8>, Box<dyn Error>> {
        unimplemented!()
    }
}

/// Every capability provider must implement this trait
pub trait CapabilityProvider: Any + Send + Sync {
    /// This function will be called on the provider when the host runtime is ready and has configured a dispatcher
    fn configure_dispatch(
        &self,
        dispatcher: Box<dyn Dispatcher>,
        identity: ModuleIdentity,
    ) -> Result<(), Box<dyn Error>>;
    /// The capability provider will return either one of the well-known capability IDs or a custom capability ID using `category:id` notation
    fn capability_id(&self) -> &'static str;
    /// The human-readable, friendly name of this capability provider. By convention, the provider should include its specific implementation,
    /// .e.g. include "Redis" in the name for a Redis-based capability provider.
    fn name(&self) -> &'static str;
    /// This function is called by the host runtime when a guest module is requesting a command be executed by the capability provider
    fn handle_call(&self, op: &str, msg: &[u8]) -> Result<Vec<u8>, Box<dyn Error>>;
}

/// Represents a unique identity for a guest module
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ModuleIdentity {
    /// The primary key of the module in prefix-encoded format (will start with the letter 'M')
    pub module: String,
    /// The primary key of the issuer/signer of the module. This will start with any one of the valid signer prefixes
    pub issuer: String,
    /// A list of capability attestations for the module
    pub capabilities: Vec<String>,
}

/// Wraps a constructor inside an FFI function to allow the `CapabilityProvider` trait implementation
/// to be instantiated and used by the host runtime
#[macro_export]
macro_rules! capability_provider {
    ($provider_type:ty, $constructor:path) => {
        #[no_mangle]
        pub extern "C" fn __capability_provider_create(
        ) -> *mut $crate::capabilities::CapabilityProvider {
            let constructor: fn() -> $provider_type = $constructor;
            let object = constructor();
            let boxed: Box<$crate::capabilities::CapabilityProvider> = Box::new(object);
            Box::into_raw(boxed)
        }
    };
}