1use crate::Result;
2use libloading::Library;
3use libloading::Symbol;
4use std::ffi::OsStr;
5use wascc_codec::{
6 capabilities::{CapabilityDescriptor, CapabilityProvider, OP_GET_CAPABILITY_DESCRIPTOR},
7 deserialize, SYSTEM_ACTOR,
8};
9
10pub struct NativeCapability {
14 pub(crate) plugin: Box<dyn CapabilityProvider>,
15 pub(crate) binding_name: String,
16 pub(crate) descriptor: CapabilityDescriptor,
17 #[allow(dead_code)]
20 library: Option<Library>,
21}
22
23impl NativeCapability {
24 pub fn from_file<P: AsRef<OsStr>>(
28 filename: P,
29 binding_target_name: Option<String>,
30 ) -> Result<Self> {
31 type PluginCreate = unsafe fn() -> *mut dyn CapabilityProvider;
32
33 let library = Library::new(filename.as_ref())?;
34
35 let plugin = unsafe {
36 let constructor: Symbol<PluginCreate> = library.get(b"__capability_provider_create")?;
37 let boxed_raw = constructor();
38
39 Box::from_raw(boxed_raw)
40 };
41 let descriptor = get_descriptor(&plugin)?;
42 let binding = binding_target_name.unwrap_or("default".to_string());
43 info!(
44 "Loaded native capability provider '{}' v{} ({}) for {}/{}",
45 descriptor.name, descriptor.version, descriptor.revision, descriptor.id, binding
46 );
47
48 Ok(NativeCapability {
49 plugin,
50 descriptor,
51 binding_name: binding,
52 library: Some(library),
53 })
54 }
55
56 pub fn from_instance(
62 instance: impl CapabilityProvider,
63 binding_target_name: Option<String>,
64 ) -> Result<Self> {
65 let b: Box<dyn CapabilityProvider> = Box::new(instance);
66 let descriptor = get_descriptor(&b)?;
67 let binding = binding_target_name.unwrap_or("default".to_string());
68
69 info!(
70 "Loaded native capability provider '{}' v{} ({}) for {}/{}",
71 descriptor.name, descriptor.version, descriptor.revision, descriptor.id, binding
72 );
73 Ok(NativeCapability {
74 descriptor,
75 plugin: b,
76 binding_name: binding,
77 library: None,
78 })
79 }
80
81 pub fn id(&self) -> String {
83 self.descriptor.id.to_string()
84 }
85
86 pub fn name(&self) -> String {
88 self.descriptor.name.to_string()
89 }
90
91 pub fn descriptor(&self) -> &CapabilityDescriptor {
93 &self.descriptor
94 }
95}
96
97fn get_descriptor(plugin: &Box<dyn CapabilityProvider>) -> Result<CapabilityDescriptor> {
98 let res = plugin.handle_call(SYSTEM_ACTOR, OP_GET_CAPABILITY_DESCRIPTOR, &[])?;
99 let descriptor: CapabilityDescriptor = deserialize(&res)?;
100 Ok(descriptor)
101}