use crate::Result;
use libloading::Library;
use libloading::Symbol;
use std::ffi::OsStr;
use wascc_codec::{
capabilities::{CapabilityDescriptor, CapabilityProvider, OP_GET_CAPABILITY_DESCRIPTOR},
deserialize, SYSTEM_ACTOR,
};
pub struct NativeCapability {
pub(crate) plugin: Box<dyn CapabilityProvider>,
pub(crate) binding_name: String,
pub(crate) descriptor: CapabilityDescriptor,
#[allow(dead_code)]
library: Option<Library>,
}
impl NativeCapability {
pub fn from_file<P: AsRef<OsStr>>(
filename: P,
binding_target_name: Option<String>,
) -> Result<Self> {
type PluginCreate = unsafe fn() -> *mut dyn CapabilityProvider;
let library = Library::new(filename.as_ref())?;
let plugin = unsafe {
let constructor: Symbol<PluginCreate> = library.get(b"__capability_provider_create")?;
let boxed_raw = constructor();
Box::from_raw(boxed_raw)
};
let descriptor = get_descriptor(&plugin)?;
let binding = binding_target_name.unwrap_or("default".to_string());
info!(
"Loaded native capability provider '{}' v{} ({}) for {}/{}",
descriptor.name, descriptor.version, descriptor.revision, descriptor.id, binding
);
Ok(NativeCapability {
plugin,
descriptor,
binding_name: binding,
library: Some(library),
})
}
pub fn from_instance(
instance: impl CapabilityProvider,
binding_target_name: Option<String>,
) -> Result<Self> {
let b: Box<dyn CapabilityProvider> = Box::new(instance);
let descriptor = get_descriptor(&b)?;
let binding = binding_target_name.unwrap_or("default".to_string());
info!(
"Loaded native capability provider '{}' v{} ({}) for {}/{}",
descriptor.name, descriptor.version, descriptor.revision, descriptor.id, binding
);
Ok(NativeCapability {
descriptor,
plugin: b,
binding_name: binding,
library: None,
})
}
pub fn id(&self) -> String {
self.descriptor.id.to_string()
}
pub fn name(&self) -> String {
self.descriptor.name.to_string()
}
pub fn descriptor(&self) -> &CapabilityDescriptor {
&self.descriptor
}
}
fn get_descriptor(plugin: &Box<dyn CapabilityProvider>) -> Result<CapabilityDescriptor> {
let res = plugin.handle_call(SYSTEM_ACTOR, OP_GET_CAPABILITY_DESCRIPTOR, &[])?;
let descriptor: CapabilityDescriptor = deserialize(&res)?;
Ok(descriptor)
}