1use super::ffi;
4use crate::{
5 instance::module::InnerInstance, types::WasmEdgeString, utils, Instance, WasmEdgeResult,
6};
7
8use std::ffi::CString;
9use wasmedge_types::error::{PluginError, WasmEdgeError};
10
11#[derive(Debug)]
13pub struct PluginManager {}
14impl PluginManager {
15 pub fn load_plugins_from_default_paths() {
23 unsafe { ffi::WasmEdge_PluginLoadWithDefaultPaths() }
24 }
25
26 pub fn load_plugins(path: impl AsRef<std::path::Path>) -> WasmEdgeResult<()> {
40 let c_path = utils::path_to_cstring(path.as_ref())?;
41 unsafe { ffi::WasmEdge_PluginLoadFromPath(c_path.as_ptr()) }
42
43 Ok(())
44 }
45
46 #[cfg(feature = "wasi_nn")]
47 #[cfg_attr(docsrs, doc(cfg(feature = "wasi_nn")))]
48 pub fn nn_preload(preloads: Vec<&str>) {
49 let c_args: Vec<CString> = preloads
50 .iter()
51 .map(|&x| std::ffi::CString::new(x).unwrap())
52 .collect();
53 let c_strs: Vec<*const ::std::os::raw::c_char> =
54 c_args.iter().map(|x| x.as_ptr()).collect();
55 let len = c_strs.len() as u32;
56 unsafe { ffi::WasmEdge_PluginInitWASINN(c_strs.as_ptr(), len) }
57 }
58
59 pub fn count() -> u32 {
61 unsafe { ffi::WasmEdge_PluginListPluginsLength() }
62 }
63
64 pub fn names() -> Vec<String> {
66 let count = Self::count();
67 let mut names = Vec::with_capacity(count as usize);
68
69 unsafe {
70 ffi::WasmEdge_PluginListPlugins(names.as_mut_ptr(), count);
71 names.set_len(count as usize);
72 };
73
74 names.into_iter().map(|x| x.into()).collect::<Vec<String>>()
75 }
76
77 pub fn find(name: impl AsRef<str>) -> WasmEdgeResult<Plugin> {
87 let plugin_name: WasmEdgeString = name.as_ref().into();
88
89 let ctx = unsafe { ffi::WasmEdge_PluginFind(plugin_name.as_raw()) };
90
91 match ctx.is_null() {
92 true => Err(Box::new(WasmEdgeError::Plugin(PluginError::NotFound(
93 name.as_ref().into(),
94 )))),
95 false => Ok(Plugin {
96 inner: InnerPlugin(ctx as *mut _),
97 }),
98 }
99 }
100
101 pub fn create_plugin_instance(
102 pname: impl AsRef<str>,
103 mname: impl AsRef<str>,
104 ) -> WasmEdgeResult<Instance> {
105 let plugin = Self::find(pname.as_ref())?;
106 plugin.mod_instance(mname.as_ref())
107 }
108
109 #[cfg(all(
117 target_os = "linux",
118 feature = "wasmedge_process",
119 not(feature = "static")
120 ))]
121 #[cfg_attr(
122 docsrs,
123 doc(cfg(all(
124 target_os = "linux",
125 feature = "wasmedge_process",
126 not(feature = "static")
127 )))
128 )]
129 pub fn init_wasmedge_process(allowed_cmds: Option<Vec<&str>>, allowed: bool) {
130 let cstr_cmds: Vec<_> = match allowed_cmds {
132 Some(cmds) => cmds
133 .iter()
134 .map(|&x| std::ffi::CString::new(x).unwrap())
135 .collect(),
136 None => vec![],
137 };
138 let mut p_cmds: Vec<_> = cstr_cmds.iter().map(|x| x.as_ptr()).collect();
139 let p_cmds_len = p_cmds.len();
140 p_cmds.push(std::ptr::null());
141
142 unsafe {
143 ffi::WasmEdge_ModuleInstanceInitWasmEdgeProcess(
144 p_cmds.as_ptr(),
145 p_cmds_len as u32,
146 allowed,
147 )
148 }
149 }
150}
151
152#[derive(Debug, Clone, Copy)]
154pub struct Plugin {
155 pub(crate) inner: InnerPlugin,
156}
157impl Plugin {
158 pub fn name(&self) -> String {
160 let name = unsafe { ffi::WasmEdge_PluginGetPluginName(self.inner.0) };
161 name.into()
162 }
163
164 pub fn mod_count(&self) -> u32 {
166 unsafe { ffi::WasmEdge_PluginListModuleLength(self.inner.0) }
167 }
168
169 pub fn mod_names(&self) -> Vec<String> {
171 let count = self.mod_count();
172 let mut names = Vec::with_capacity(count as usize);
173
174 unsafe {
175 ffi::WasmEdge_PluginListModule(self.inner.0, names.as_mut_ptr(), count);
176 names.set_len(count as usize);
177 }
178
179 names.into_iter().map(|x| x.into()).collect::<Vec<String>>()
180 }
181
182 pub fn mod_instance(&self, name: impl AsRef<str>) -> WasmEdgeResult<Instance> {
192 let mod_name: WasmEdgeString = name.as_ref().into();
193
194 let ctx = unsafe { ffi::WasmEdge_PluginCreateModule(self.inner.0, mod_name.as_raw()) };
195
196 match ctx.is_null() {
197 true => Err(Box::new(WasmEdgeError::Plugin(PluginError::Create(
198 name.as_ref().into(),
199 )))),
200 false => Ok(Instance {
201 inner: InnerInstance(ctx),
202 }),
203 }
204 }
205
206 pub unsafe fn as_ptr(&self) -> *const ffi::WasmEdge_PluginContext {
210 self.inner.0 as *const _
211 }
212}
213
214#[derive(Debug, Clone, Copy)]
215pub(crate) struct InnerPlugin(pub(crate) *mut ffi::WasmEdge_PluginContext);
216unsafe impl Send for InnerPlugin {}
217unsafe impl Sync for InnerPlugin {}
218
219#[derive(Debug, Clone, Copy, PartialEq, Eq)]
221pub enum ProgramOptionType {
222 None = 0,
223 Toggle = 1,
224 I8 = 2,
225 I16 = 3,
226 I32 = 4,
227 I64 = 5,
228 U8 = 6,
229 U16 = 7,
230 U32 = 8,
231 U64 = 9,
232 F32 = 10,
233 F64 = 11,
234 String = 12,
235}
236impl From<ffi::WasmEdge_ProgramOptionType> for ProgramOptionType {
237 fn from(ty: ffi::WasmEdge_ProgramOptionType) -> Self {
238 match ty {
239 ffi::WasmEdge_ProgramOptionType_None => ProgramOptionType::None,
240 ffi::WasmEdge_ProgramOptionType_Toggle => ProgramOptionType::Toggle,
241 ffi::WasmEdge_ProgramOptionType_Int8 => ProgramOptionType::I8,
242 ffi::WasmEdge_ProgramOptionType_Int16 => ProgramOptionType::I16,
243 ffi::WasmEdge_ProgramOptionType_Int32 => ProgramOptionType::I32,
244 ffi::WasmEdge_ProgramOptionType_Int64 => ProgramOptionType::I64,
245 ffi::WasmEdge_ProgramOptionType_UInt8 => ProgramOptionType::U8,
246 ffi::WasmEdge_ProgramOptionType_UInt16 => ProgramOptionType::U16,
247 ffi::WasmEdge_ProgramOptionType_UInt32 => ProgramOptionType::U32,
248 ffi::WasmEdge_ProgramOptionType_UInt64 => ProgramOptionType::U64,
249 ffi::WasmEdge_ProgramOptionType_Float => ProgramOptionType::F32,
250 ffi::WasmEdge_ProgramOptionType_Double => ProgramOptionType::F64,
251 ffi::WasmEdge_ProgramOptionType_String => ProgramOptionType::String,
252 _ => {
253 panic!("[wasmedge-sys] Unsupported ffi::WasmEdge_ProgramOptionType value: {ty}");
254 }
255 }
256 }
257}
258impl From<ProgramOptionType> for ffi::WasmEdge_ProgramOptionType {
259 fn from(value: ProgramOptionType) -> Self {
260 match value {
261 ProgramOptionType::None => ffi::WasmEdge_ProgramOptionType_None,
262 ProgramOptionType::Toggle => ffi::WasmEdge_ProgramOptionType_Toggle,
263 ProgramOptionType::I8 => ffi::WasmEdge_ProgramOptionType_Int8,
264 ProgramOptionType::I16 => ffi::WasmEdge_ProgramOptionType_Int16,
265 ProgramOptionType::I32 => ffi::WasmEdge_ProgramOptionType_Int32,
266 ProgramOptionType::I64 => ffi::WasmEdge_ProgramOptionType_Int64,
267 ProgramOptionType::U8 => ffi::WasmEdge_ProgramOptionType_UInt8,
268 ProgramOptionType::U16 => ffi::WasmEdge_ProgramOptionType_UInt16,
269 ProgramOptionType::U32 => ffi::WasmEdge_ProgramOptionType_UInt32,
270 ProgramOptionType::U64 => ffi::WasmEdge_ProgramOptionType_UInt64,
271 ProgramOptionType::F32 => ffi::WasmEdge_ProgramOptionType_Float,
272 ProgramOptionType::F64 => ffi::WasmEdge_ProgramOptionType_Double,
273 ProgramOptionType::String => ffi::WasmEdge_ProgramOptionType_String,
274 }
275 }
276}
277
278#[derive(Debug)]
280pub struct ProgramOption {
281 name: CString,
282 desc: CString,
283 pub inner: ffi::WasmEdge_ProgramOption,
284}
285impl ProgramOption {
286 pub fn create(
288 name: impl AsRef<str>,
289 desc: impl AsRef<str>,
290 ty: ProgramOptionType,
291 ) -> WasmEdgeResult<Self> {
292 let name = std::ffi::CString::new(name.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
293
294 let desc = std::ffi::CString::new(desc.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
295
296 let mut po = Self {
297 name,
298 desc,
299 inner: ffi::WasmEdge_ProgramOption {
300 Name: std::ptr::null(),
301 Description: std::ptr::null(),
302 Type: ty.into(),
303 Storage: std::ptr::null_mut(),
304 DefaultValue: std::ptr::null(),
305 },
306 };
307 po.inner.Name = po.name.as_ptr();
308 po.inner.Description = po.desc.as_ptr();
309
310 Ok(po)
311 }
312}
313unsafe impl Send for ProgramOption {}
314unsafe impl Sync for ProgramOption {}
315
316#[derive(Debug)]
318pub struct ModuleDescriptor {
319 name: CString,
320 desc: CString,
321 create: Option<ModuleInstanceCreateFn>,
322 inner: ffi::WasmEdge_ModuleDescriptor,
323}
324impl ModuleDescriptor {
325 pub fn create(
327 name: impl AsRef<str>,
328 desc: impl AsRef<str>,
329 f: Option<ModuleInstanceCreateFn>,
330 ) -> WasmEdgeResult<Self> {
331 let name = std::ffi::CString::new(name.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
333
334 let desc = std::ffi::CString::new(desc.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
336
337 let mut md = Self {
338 name,
339 desc,
340 create: f,
341 inner: ffi::WasmEdge_ModuleDescriptor {
342 Name: std::ptr::null(),
343 Description: std::ptr::null(),
344 Create: None,
345 },
346 };
347 md.inner.Name = md.name.as_ptr();
348 md.inner.Description = md.desc.as_ptr();
349 md.inner.Create = md.create;
350
351 Ok(md)
352 }
353
354 #[cfg(feature = "ffi")]
356 #[cfg_attr(docsrs, doc(cfg(feature = "ffi")))]
357 pub fn as_raw_ptr(&self) -> *const ffi::WasmEdge_ModuleDescriptor {
358 &self.inner
359 }
360}
361
362pub type ModuleInstanceCreateFn = unsafe extern "C" fn(
364 arg1: *const ffi::WasmEdge_ModuleDescriptor,
365) -> *mut ffi::WasmEdge_ModuleInstanceContext;
366
367#[derive(Debug)]
369pub struct PluginVersion {
370 pub major: u32,
371 pub minor: u32,
372 pub patch: u32,
373 pub build: u32,
374}
375impl PluginVersion {
376 pub fn create(major: u32, minor: u32, patch: u32, build: u32) -> Self {
378 Self {
379 major,
380 minor,
381 patch,
382 build,
383 }
384 }
385}
386impl From<PluginVersion> for ffi::WasmEdge_PluginVersionData {
387 fn from(value: PluginVersion) -> Self {
388 Self {
389 Major: value.major,
390 Minor: value.minor,
391 Patch: value.patch,
392 Build: value.build,
393 }
394 }
395}
396
397#[derive(Debug)]
399pub struct PluginDescriptor {
400 name: CString,
401 desc: CString,
402 module_descriptors_name_desc: Vec<(CString, CString)>,
403 module_descriptors: Vec<ffi::WasmEdge_ModuleDescriptor>,
404 program_options_name_desc: Vec<(CString, CString)>,
405 program_options: Vec<ffi::WasmEdge_ProgramOption>,
406 inner: ffi::WasmEdge_PluginDescriptor,
407}
408impl PluginDescriptor {
409 pub fn create(
410 name: impl AsRef<str>,
411 desc: impl AsRef<str>,
412 version: PluginVersion,
413 ) -> WasmEdgeResult<Self> {
414 let name = std::ffi::CString::new(name.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
416
417 let desc = std::ffi::CString::new(desc.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
419
420 let mut pd = Self {
421 name,
422 desc,
423 module_descriptors_name_desc: Vec::new(),
424 module_descriptors: Vec::new(),
425 program_options_name_desc: Vec::new(),
426 program_options: Vec::new(),
427 inner: ffi::WasmEdge_PluginDescriptor {
428 Name: std::ptr::null(),
429 Description: std::ptr::null(),
430 APIVersion: ffi::WasmEdge_Plugin_CurrentAPIVersion,
431 Version: version.into(),
432 ModuleCount: 0,
433 ModuleDescriptions: std::ptr::null_mut(),
434 ProgramOptionCount: 0,
435 ProgramOptions: std::ptr::null_mut(),
436 },
437 };
438 pd.inner.Name = pd.name.as_ptr();
439 pd.inner.Description = pd.desc.as_ptr();
440
441 Ok(pd)
442 }
443
444 pub fn add_module_descriptor(
445 mut self,
446 name: impl AsRef<str>,
447 desc: impl AsRef<str>,
448 f: Option<ModuleInstanceCreateFn>,
449 ) -> WasmEdgeResult<Self> {
450 let name = std::ffi::CString::new(name.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
452
453 let desc = std::ffi::CString::new(desc.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
455
456 self.module_descriptors
457 .push(ffi::WasmEdge_ModuleDescriptor {
458 Name: name.as_ptr(),
459 Description: desc.as_ptr(),
460 Create: f,
461 });
462 self.module_descriptors_name_desc.push((name, desc));
463
464 self.inner.ModuleCount = self.module_descriptors.len() as u32;
465 self.inner.ModuleDescriptions = self.module_descriptors.as_mut_ptr();
466
467 Ok(self)
468 }
469
470 pub fn add_program_option(
471 mut self,
472 name: impl AsRef<str>,
473 desc: impl AsRef<str>,
474 ty: ProgramOptionType,
475 ) -> WasmEdgeResult<Self> {
476 let name = std::ffi::CString::new(name.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
477
478 let desc = std::ffi::CString::new(desc.as_ref()).map_err(WasmEdgeError::FoundNulByte)?;
479
480 self.program_options.push(ffi::WasmEdge_ProgramOption {
481 Name: name.as_ptr(),
482 Description: desc.as_ptr(),
483 Type: ty.into(),
484 Storage: std::ptr::null_mut(),
485 DefaultValue: std::ptr::null(),
486 });
487 self.program_options_name_desc.push((name, desc));
488
489 self.inner.ProgramOptionCount = self.program_options.len() as u32;
490 self.inner.ProgramOptions = self.program_options.as_mut_ptr();
491
492 Ok(self)
493 }
494
495 #[cfg(feature = "ffi")]
497 #[cfg_attr(docsrs, doc(cfg(feature = "ffi")))]
498 pub fn as_raw_ptr(&self) -> *const ffi::WasmEdge_PluginDescriptor {
499 &self.inner
500 }
501}
502
503pub type PluginModule = Instance;
505
506#[cfg(test)]
507mod tests {
508
509 #[cfg(all(
510 target_os = "linux",
511 feature = "wasmedge_process",
512 not(feature = "static")
513 ))]
514 #[test]
515 #[ignore]
516 fn test_plugin_wasmedge_process() {
517 use crate::AsInstance;
518
519 use super::*;
520
521 PluginManager::load_plugins_from_default_paths();
522 assert!(PluginManager::count() >= 1);
523 assert!(PluginManager::names()
524 .iter()
525 .any(|x| x == "wasmedge_process"));
526
527 let result = PluginManager::find("wasmedge_process");
529 assert!(result.is_ok());
530 let plugin = result.unwrap();
531 assert_eq!(plugin.name(), "wasmedge_process");
532 assert_eq!(plugin.mod_count(), 1);
533 assert!(plugin.mod_names().iter().any(|x| x == "wasmedge_process"));
534
535 let result = plugin.mod_instance("wasmedge_process");
537 assert!(result.is_ok());
538 let instance = result.unwrap();
539
540 assert_eq!(instance.name().unwrap(), "wasmedge_process");
541 assert_eq!(instance.func_len(), 11);
542 assert_eq!(
543 instance.func_names().unwrap(),
544 [
545 "wasmedge_process_add_arg",
546 "wasmedge_process_add_env",
547 "wasmedge_process_add_stdin",
548 "wasmedge_process_get_exit_code",
549 "wasmedge_process_get_stderr",
550 "wasmedge_process_get_stderr_len",
551 "wasmedge_process_get_stdout",
552 "wasmedge_process_get_stdout_len",
553 "wasmedge_process_run",
554 "wasmedge_process_set_prog_name",
555 "wasmedge_process_set_timeout",
556 ]
557 );
558 assert_eq!(instance.mem_len(), 0);
559 assert_eq!(instance.table_len(), 0);
560 assert_eq!(instance.global_len(), 0);
561 }
562
563 #[cfg(all(target_os = "linux", feature = "wasi_crypto", not(feature = "static")))]
564 #[test]
565 fn test_plugin_wasi_crypto() {
566 use crate::AsInstance;
567
568 use super::*;
569
570 PluginManager::load_plugins_from_default_paths();
571 assert!(PluginManager::count() >= 1);
572 assert!(
573 PluginManager::names().iter().any(|x| x == "wasi_crypto"),
574 "Not found the `wasi_crypto` plugin"
575 );
576
577 let result = PluginManager::find("wasi_crypto");
579 assert!(result.is_ok());
580 let plugin = result.unwrap();
581 assert_eq!(plugin.name(), "wasi_crypto");
582 assert_eq!(plugin.mod_count(), 5);
583 assert_eq!(
584 plugin.mod_names(),
585 [
586 "wasi_crypto_asymmetric_common",
587 "wasi_crypto_common",
588 "wasi_crypto_kx",
589 "wasi_crypto_signatures",
590 "wasi_crypto_symmetric",
591 ]
592 );
593
594 {
596 let result = plugin.mod_instance("wasi_crypto_asymmetric_common");
597 assert!(result.is_ok());
598 let instance = result.unwrap();
599 assert_eq!(
600 instance.name().unwrap(),
601 "wasi_ephemeral_crypto_asymmetric_common"
602 );
603 assert_eq!(instance.func_len(), 20);
604 assert_eq!(
605 instance.func_names().unwrap(),
606 [
607 "keypair_close",
608 "keypair_export",
609 "keypair_from_id",
610 "keypair_from_pk_and_sk",
611 "keypair_generate",
612 "keypair_generate_managed",
613 "keypair_id",
614 "keypair_import",
615 "keypair_publickey",
616 "keypair_replace_managed",
617 "keypair_secretkey",
618 "keypair_store_managed",
619 "publickey_close",
620 "publickey_export",
621 "publickey_from_secretkey",
622 "publickey_import",
623 "publickey_verify",
624 "secretkey_close",
625 "secretkey_export",
626 "secretkey_import",
627 ],
628 );
629 }
630
631 {
633 let result = plugin.mod_instance("wasi_crypto_common");
634 assert!(result.is_ok());
635 let instance = result.unwrap();
636 assert_eq!(instance.name().unwrap(), "wasi_ephemeral_crypto_common");
637 assert_eq!(instance.func_len(), 10);
638 assert_eq!(
639 instance.func_names().unwrap(),
640 [
641 "array_output_len",
642 "array_output_pull",
643 "options_close",
644 "options_open",
645 "options_set",
646 "options_set_guest_buffer",
647 "options_set_u64",
648 "secrets_manager_close",
649 "secrets_manager_invalidate",
650 "secrets_manager_open",
651 ],
652 );
653 }
654
655 {
657 let result = plugin.mod_instance("wasi_crypto_kx");
658 assert!(result.is_ok());
659 let instance = result.unwrap();
660 assert_eq!(instance.name().unwrap(), "wasi_ephemeral_crypto_kx");
661 assert_eq!(instance.func_len(), 3);
662 assert_eq!(
663 instance.func_names().unwrap(),
664 ["kx_decapsulate", "kx_dh", "kx_encapsulate",],
665 );
666 }
667
668 {
670 let result = plugin.mod_instance("wasi_crypto_signatures");
671 assert!(result.is_ok());
672 let instance = result.unwrap();
673 assert_eq!(instance.name().unwrap(), "wasi_ephemeral_crypto_signatures");
674 assert_eq!(instance.func_len(), 11);
675 assert_eq!(
676 instance.func_names().unwrap(),
677 [
678 "signature_close",
679 "signature_export",
680 "signature_import",
681 "signature_state_close",
682 "signature_state_open",
683 "signature_state_sign",
684 "signature_state_update",
685 "signature_verification_state_close",
686 "signature_verification_state_open",
687 "signature_verification_state_update",
688 "signature_verification_state_verify",
689 ],
690 );
691 }
692
693 {
695 let result = plugin.mod_instance("wasi_crypto_symmetric");
696 assert!(result.is_ok());
697 let instance = result.unwrap();
698 assert_eq!(instance.name().unwrap(), "wasi_ephemeral_crypto_symmetric");
699 assert_eq!(instance.func_len(), 28);
700 assert_eq!(
701 instance.func_names().unwrap(),
702 [
703 "symmetric_key_close",
704 "symmetric_key_export",
705 "symmetric_key_from_id",
706 "symmetric_key_generate",
707 "symmetric_key_generate_managed",
708 "symmetric_key_id",
709 "symmetric_key_import",
710 "symmetric_key_replace_managed",
711 "symmetric_key_store_managed",
712 "symmetric_state_absorb",
713 "symmetric_state_clone",
714 "symmetric_state_close",
715 "symmetric_state_decrypt",
716 "symmetric_state_decrypt_detached",
717 "symmetric_state_encrypt",
718 "symmetric_state_encrypt_detached",
719 "symmetric_state_max_tag_len",
720 "symmetric_state_open",
721 "symmetric_state_options_get",
722 "symmetric_state_options_get_u64",
723 "symmetric_state_ratchet",
724 "symmetric_state_squeeze",
725 "symmetric_state_squeeze_key",
726 "symmetric_state_squeeze_tag",
727 "symmetric_tag_close",
728 "symmetric_tag_len",
729 "symmetric_tag_pull",
730 "symmetric_tag_verify",
731 ],
732 );
733 }
734 }
735}