mirror of
https://github.com/extism/extism.git
synced 2026-01-11 14:58:01 -05:00
Compare commits
2 Commits
v1.4.1
...
wasi-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24d3a667ce | ||
|
|
ba5a12064f |
@@ -251,6 +251,19 @@ int32_t extism_plugin_call_with_host_context(ExtismPlugin *plugin,
|
||||
ExtismSize data_len,
|
||||
void *host_context);
|
||||
|
||||
/**
|
||||
* Call a function with host context.
|
||||
*
|
||||
* `func_name`: is the function to call
|
||||
* `data`: is the input data
|
||||
* `data_len`: is the length of `data`
|
||||
* `host_context`: a pointer to context data that will be available in host functions
|
||||
*/
|
||||
int32_t extism_plugin_call_wasi_command(ExtismPlugin *plugin,
|
||||
const char *func_name,
|
||||
const uint8_t *data,
|
||||
ExtismSize data_len);
|
||||
|
||||
/**
|
||||
* Get the error associated with a `Plugin`
|
||||
*/
|
||||
|
||||
@@ -327,13 +327,18 @@ impl CurrentPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
// Enable WASI output, typically used for debugging purposes
|
||||
if std::env::var("EXTISM_ENABLE_WASI_OUTPUT").is_ok() {
|
||||
// Enable WASI output, typically used for debugging purposes
|
||||
ctx.set_stderr(Box::new(wasi_common::sync::stdio::stderr()));
|
||||
ctx.set_stdout(Box::new(wasi_common::sync::stdio::stdout()));
|
||||
}
|
||||
|
||||
Some(Wasi { ctx })
|
||||
Some(Wasi {
|
||||
ctx,
|
||||
|
||||
stderr: None,
|
||||
stdout: None,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
@@ -4,6 +4,9 @@ use crate::*;
|
||||
pub struct Wasi {
|
||||
/// wasi
|
||||
pub ctx: wasi_common::WasiCtx,
|
||||
|
||||
pub stdout: Option<std::sync::Arc<std::sync::RwLock<Vec<u8>>>>,
|
||||
pub stderr: Option<std::sync::Arc<std::sync::RwLock<Vec<u8>>>>,
|
||||
}
|
||||
|
||||
/// InternalExt provides a unified way of acessing `memory`, `store` and `internal` values
|
||||
|
||||
@@ -4,6 +4,8 @@ use std::{
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use wasi_common::pipe::{ReadPipe, WritePipe};
|
||||
|
||||
use crate::*;
|
||||
|
||||
pub const EXTISM_ENV_MODULE: &str = "extism:host/env";
|
||||
@@ -483,6 +485,7 @@ impl Plugin {
|
||||
input: *const u8,
|
||||
mut len: usize,
|
||||
host_context: Option<Rooted<ExternRef>>,
|
||||
wasi_input: bool,
|
||||
) -> Result<(), Error> {
|
||||
self.output = Output::default();
|
||||
self.clear_error()?;
|
||||
@@ -506,6 +509,30 @@ impl Plugin {
|
||||
self.reset()?;
|
||||
let handle = self.current_plugin_mut().memory_new(bytes)?;
|
||||
|
||||
if wasi_input {
|
||||
if let Some(wasi) = &mut self.current_plugin_mut().wasi {
|
||||
wasi.ctx.set_stdin(Box::new(ReadPipe::from(bytes)));
|
||||
|
||||
if let Some(stdout) = &mut wasi.stdout {
|
||||
stdout.write().unwrap().clear();
|
||||
} else {
|
||||
let stdout = std::sync::Arc::new(std::sync::RwLock::new(vec![0; 1024]));
|
||||
let x = WritePipe::from_shared(stdout.clone());
|
||||
wasi.ctx.set_stdout(Box::new(x));
|
||||
wasi.stdout = Some(stdout);
|
||||
}
|
||||
|
||||
if let Some(stderr) = &mut wasi.stderr {
|
||||
stderr.write().unwrap().clear();
|
||||
} else {
|
||||
let stderr = std::sync::Arc::new(std::sync::RwLock::new(vec![0; 1024]));
|
||||
let x = WritePipe::from_shared(stderr.clone());
|
||||
wasi.ctx.set_stderr(Box::new(x));
|
||||
wasi.stderr = Some(stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(f) = self
|
||||
.linker
|
||||
.get(&mut self.store, EXTISM_ENV_MODULE, "input_set")
|
||||
@@ -702,6 +729,7 @@ impl Plugin {
|
||||
name: impl AsRef<str>,
|
||||
input: impl AsRef<[u8]>,
|
||||
host_context: Option<Rooted<ExternRef>>,
|
||||
wasi_input: bool,
|
||||
) -> Result<i32, (Error, i32)> {
|
||||
let name = name.as_ref();
|
||||
let input = input.as_ref();
|
||||
@@ -715,7 +743,7 @@ impl Plugin {
|
||||
|
||||
self.instantiate(lock).map_err(|e| (e, -1))?;
|
||||
|
||||
self.set_input(input.as_ptr(), input.len(), host_context)
|
||||
self.set_input(input.as_ptr(), input.len(), host_context, wasi_input)
|
||||
.map_err(|x| (x, -1))?;
|
||||
|
||||
let func = match self.get_func(lock, name) {
|
||||
@@ -897,7 +925,7 @@ impl Plugin {
|
||||
let lock = self.instance.clone();
|
||||
let mut lock = lock.lock().unwrap();
|
||||
let data = input.to_bytes()?;
|
||||
self.raw_call(&mut lock, name, data, None)
|
||||
self.raw_call(&mut lock, name, data, None, false)
|
||||
.map_err(|e| e.0)
|
||||
.and_then(move |rc| {
|
||||
if rc != 0 {
|
||||
@@ -923,11 +951,53 @@ impl Plugin {
|
||||
let mut lock = lock.lock().unwrap();
|
||||
let data = input.to_bytes()?;
|
||||
let ctx = ExternRef::new(&mut self.store, host_context)?;
|
||||
self.raw_call(&mut lock, name, data, Some(ctx))
|
||||
self.raw_call(&mut lock, name, data, Some(ctx), false)
|
||||
.map_err(|e| e.0)
|
||||
.and_then(move |_| self.output())
|
||||
}
|
||||
|
||||
/// Call a WASI command module, this will use Extism input as stdin and WASI stdout as the Extism
|
||||
/// output
|
||||
pub fn call_wasi_command<'a, T: ToBytes<'a>, U: FromBytesOwned>(
|
||||
&mut self,
|
||||
input: T,
|
||||
) -> Result<U, (Error, Vec<u8>)> {
|
||||
let lock = self.instance.clone();
|
||||
let mut lock = lock.lock().unwrap();
|
||||
let data = input.to_bytes().map_err(|x| (x, vec![]))?;
|
||||
self.raw_call(&mut lock, "_start", data, None, true)
|
||||
.map_err(|e| {
|
||||
if let Some(wasi) = &self.current_plugin_mut().wasi {
|
||||
if let Some(stderr) = &wasi.stderr {
|
||||
return (e.0, stderr.read().unwrap().clone());
|
||||
}
|
||||
}
|
||||
(e.0, vec![])
|
||||
})
|
||||
.and_then(move |rc| {
|
||||
if rc != 0 {
|
||||
let e = Error::msg(format!("Returned non-zero exit code: {rc}"));
|
||||
if let Some(wasi) = &self.current_plugin_mut().wasi {
|
||||
if let Some(stderr) = &wasi.stderr {
|
||||
return Err((e, stderr.read().unwrap().clone()));
|
||||
}
|
||||
}
|
||||
Err((e, vec![]))
|
||||
} else {
|
||||
if let Some(wasi) = &self.current_plugin_mut().wasi {
|
||||
if let Some(stdout) = &wasi.stdout {
|
||||
return U::from_bytes_owned(&*stdout.write().unwrap())
|
||||
.map_err(|e| (e, vec![]));
|
||||
} else {
|
||||
self.output().map_err(|e| (e, vec![]))
|
||||
}
|
||||
} else {
|
||||
self.output().map_err(|e| (e, vec![]))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Similar to `Plugin::call`, but returns the Extism error code along with the
|
||||
/// `Error`. It is assumed if `Ok(_)` is returned that the error code was `0`.
|
||||
///
|
||||
@@ -942,7 +1012,7 @@ impl Plugin {
|
||||
let lock = self.instance.clone();
|
||||
let mut lock = lock.lock().unwrap();
|
||||
let data = input.to_bytes().map_err(|e| (e, -1))?;
|
||||
self.raw_call(&mut lock, name, data, None)
|
||||
self.raw_call(&mut lock, name, data, None, false)
|
||||
.and_then(move |_| self.output().map_err(|e| (e, -1)))
|
||||
}
|
||||
|
||||
|
||||
@@ -522,7 +522,47 @@ pub unsafe extern "C" fn extism_plugin_call_with_host_context(
|
||||
Err(e) => return plugin.return_error(&mut lock, e, -1),
|
||||
Ok(x) => x,
|
||||
};
|
||||
let res = plugin.raw_call(&mut lock, name, input, Some(r));
|
||||
let res = plugin.raw_call(&mut lock, name, input, Some(r), false);
|
||||
match res {
|
||||
Err((e, rc)) => plugin.return_error(&mut lock, e, rc),
|
||||
Ok(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
/// Call a function with host context.
|
||||
///
|
||||
/// `func_name`: is the function to call
|
||||
/// `data`: is the input data
|
||||
/// `data_len`: is the length of `data`
|
||||
/// `host_context`: a pointer to context data that will be available in host functions
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn extism_plugin_call_wasi_command(
|
||||
plugin: *mut Plugin,
|
||||
func_name: *const c_char,
|
||||
data: *const u8,
|
||||
data_len: Size,
|
||||
) -> i32 {
|
||||
if plugin.is_null() {
|
||||
return -1;
|
||||
}
|
||||
let plugin = &mut *plugin;
|
||||
let lock = plugin.instance.clone();
|
||||
let mut lock = lock.lock().unwrap();
|
||||
|
||||
// Get function name
|
||||
let name = std::ffi::CStr::from_ptr(func_name);
|
||||
let name = match name.to_str() {
|
||||
Ok(name) => name,
|
||||
Err(e) => return plugin.return_error(&mut lock, e, -1),
|
||||
};
|
||||
|
||||
trace!(
|
||||
plugin = plugin.id.to_string(),
|
||||
"calling function {} using extism_plugin_call",
|
||||
name
|
||||
);
|
||||
let input = std::slice::from_raw_parts(data, data_len as usize);
|
||||
let res = plugin.raw_call(&mut lock, name, input, None, true);
|
||||
match res {
|
||||
Err((e, rc)) => plugin.return_error(&mut lock, e, rc),
|
||||
Ok(x) => x,
|
||||
|
||||
Reference in New Issue
Block a user