Compare commits

..

1 Commits

Author SHA1 Message Date
zach
8263790a74 feat: add Plugin::call_with_arg 2024-04-09 10:51:08 -07:00
7 changed files with 62 additions and 79 deletions

View File

@@ -51,7 +51,6 @@ started:
| Java SDK | <img alt="Java SDK" src="https://extism.org/img/sdk-languages/java-android.svg" width="50px"/> | https://github.com/extism/java-sdk | [Sonatype](https://central.sonatype.com/artifact/org.extism.sdk/extism) |
| .NET SDK | <img alt=".NET SDK" src="https://extism.org/img/sdk-languages/dotnet.svg" width="50px"/> | https://github.com/extism/dotnet-sdk <br/>(supports C# & F#!) | [Nuget](https://www.nuget.org/packages/Extism.Sdk) |
| OCaml SDK | <img alt="OCaml SDK" src="https://extism.org/img/sdk-languages/ocaml.svg" width="50px"/> | https://github.com/extism/ocaml-sdk | [opam](https://opam.ocaml.org/packages/extism/) |
| Perl SDK | <img alt="Perl SDK" src="https://extism.org/img/sdk-languages/perl.svg" width="50px"/> | https://github.com/extism/perl-sdk | N/A |
| PHP SDK | <img alt="PHP SDK" src="https://extism.org/img/sdk-languages/php.svg" width="50px"/> | https://github.com/extism/php-sdk | [Packagist](https://packagist.org/packages/extism/extism) |
| Python SDK | <img alt="Python SDK" src="https://extism.org/img/sdk-languages/python.svg" width="50px"/> | https://github.com/extism/python-sdk | [PyPi](https://pypi.org/project/extism/) |
| Ruby SDK | <img alt="Ruby SDK" src="https://extism.org/img/sdk-languages/ruby.svg" width="50px"/> | https://github.com/extism/ruby-sdk | [RubyGems](https://rubygems.org/gems/extism) |

View File

@@ -9,8 +9,8 @@ repository.workspace = true
version.workspace = true
[dependencies]
wasmtime = ">= 18.0.0, < 19.0.0"
wasmtime-wasi = ">= 18.0.0, < 19.0.0"
wasmtime = ">= 14.0.0, < 18.0.0"
wasmtime-wasi = ">= 14.0.0, < 18.0.0"
anyhow = "1"
serde = {version = "1", features = ["derive"]}
serde_json = "1"

View File

@@ -12,7 +12,7 @@ To use the `extism` crate, you can add it to your Cargo file:
```toml
[dependencies]
extism = "1.2.0"
extism = "1.0.0"
```
## Environment variables
@@ -201,7 +201,7 @@ fn main() {
}
```
> *Note*: In order to write host functions you should get familiar with the methods on the [CurrentPlugin](https://docs.rs/extism/latest/extism/struct.CurrentPlugin.html) and [UserData](https://docs.rs/extism/latest/extism/enum.UserData.html) types.
> *Note*: In order to write host functions you should get familiar with the methods on the [Extism::CurrentPlugin](https://docs.rs/extism/latest/extism/struct.CurrentPlugin.html) and [Extism::CurrentPlugin](https://docs.rs/extism/latest/extism/struct.UserData.html) types.
Now we can invoke the event:

View File

@@ -1,6 +1,3 @@
use wasmtime::component::ResourceTable;
use wasmtime_wasi::preview2::{preview1::WasiPreview1Adapter, DirPerms, FilePerms};
use crate::*;
/// CurrentPlugin stores data that is available to the caller in PDK functions, this should
@@ -21,7 +18,6 @@ pub struct CurrentPlugin {
}
unsafe impl Send for CurrentPlugin {}
unsafe impl Sync for CurrentPlugin {}
pub(crate) struct MemoryLimiter {
bytes_left: usize,
@@ -66,11 +62,6 @@ impl wasmtime::ResourceLimiter for MemoryLimiter {
}
impl CurrentPlugin {
/// Gets `Plugin`'s ID
pub fn id(&self) -> uuid::Uuid {
self.id
}
/// Get a `MemoryHandle` from a memory offset
pub fn memory_handle(&mut self, offs: u64) -> Option<MemoryHandle> {
if offs == 0 {
@@ -298,10 +289,10 @@ impl CurrentPlugin {
) -> Result<Self, Error> {
let wasi = if wasi {
let auth = wasmtime_wasi::ambient_authority();
let mut ctx = wasmtime_wasi::preview2::WasiCtxBuilder::new();
ctx.allow_ip_name_lookup(true);
ctx.allow_tcp(true);
ctx.allow_udp(true);
let mut ctx = wasmtime_wasi::WasiCtxBuilder::new();
for (k, v) in manifest.config.iter() {
ctx.env(k, v)?;
}
if let Some(a) = &manifest.allowed_paths {
for (k, v) in a.iter() {
@@ -312,43 +303,16 @@ impl CurrentPlugin {
err.kind()
))
})?;
ctx.preopened_dir(
d,
DirPerms::READ | DirPerms::MUTATE,
FilePerms::READ | FilePerms::WRITE,
v.to_string_lossy(),
);
ctx.preopened_dir(d, v)?;
}
}
if let Some(h) = &manifest.allowed_hosts {
let h = h.clone();
ctx.socket_addr_check(move |addr, _kind| {
for host in h.iter() {
let addrs = std::net::ToSocketAddrs::to_socket_addrs(&host);
if let Ok(addrs) = addrs {
for a in addrs.into_iter() {
if addr == &a {
return true;
}
}
}
}
false
});
}
// Enable WASI output, typically used for debugging purposes
if std::env::var("EXTISM_ENABLE_WASI_OUTPUT").is_ok() {
ctx.inherit_stdout().inherit_stderr();
}
Some(Wasi {
ctx: ctx.build(),
preview2_table: ResourceTable::new(),
preview1_adapter: WasiPreview1Adapter::new(),
})
Some(Wasi { ctx: ctx.build() })
} else {
None
};

View File

@@ -3,29 +3,7 @@ use crate::*;
/// WASI context
pub struct Wasi {
/// wasi
pub ctx: wasmtime_wasi::preview2::WasiCtx,
pub preview2_table: wasmtime::component::ResourceTable,
pub preview1_adapter: wasmtime_wasi::preview2::preview1::WasiPreview1Adapter,
}
impl wasmtime_wasi::preview2::WasiView for CurrentPlugin {
fn table(&mut self) -> &mut wasmtime::component::ResourceTable {
&mut self.wasi.as_mut().unwrap().preview2_table
}
fn ctx(&mut self) -> &mut wasmtime_wasi::preview2::WasiCtx {
&mut self.wasi.as_mut().unwrap().ctx
}
}
impl wasmtime_wasi::preview2::preview1::WasiPreview1View for CurrentPlugin {
fn adapter(&self) -> &wasmtime_wasi::preview2::preview1::WasiPreview1Adapter {
&self.wasi.as_ref().unwrap().preview1_adapter
}
fn adapter_mut(&mut self) -> &mut wasmtime_wasi::preview2::preview1::WasiPreview1Adapter {
&mut self.wasi.as_mut().unwrap().preview1_adapter
}
pub ctx: wasmtime_wasi::WasiCtx,
}
/// InternalExt provides a unified way of acessing `memory`, `store` and `internal` values

View File

@@ -307,7 +307,9 @@ impl Plugin {
// If wasi is enabled then add it to the linker
if with_wasi {
wasmtime_wasi::preview2::preview1::add_to_linker_sync(&mut linker)?;
wasmtime_wasi::add_to_linker(&mut linker, |x: &mut CurrentPlugin| {
&mut x.wasi.as_mut().unwrap().ctx
})?;
}
for f in &mut imports {
@@ -666,11 +668,12 @@ impl Plugin {
// Implements the build of the `call` function, `raw_call` is also used in the SDK
// code
pub(crate) fn raw_call(
pub(crate) fn raw_call<T: 'static + Sync + Send>(
&mut self,
lock: &mut std::sync::MutexGuard<Option<Instance>>,
name: impl AsRef<str>,
input: impl AsRef<[u8]>,
arg: Option<T>,
) -> Result<i32, (Error, i32)> {
let name = name.as_ref();
let input = input.as_ref();
@@ -718,7 +721,14 @@ impl Plugin {
// Call the function
let mut results = vec![wasmtime::Val::null(); n_results];
let mut res = func.call(self.store_mut(), &[], results.as_mut_slice());
let args = if func.ty(self.store()).params().count() == 0 {
vec![]
} else {
let r = arg.map(wasmtime::ExternRef::new);
vec![wasmtime::Val::ExternRef(r)]
};
let mut res = func.call(self.store_mut(), args.as_slice(), results.as_mut_slice());
// Stop timer
self.store
@@ -803,8 +813,12 @@ impl Plugin {
}
let wasi_exit_code = e
.downcast_ref::<wasmtime_wasi::preview2::I32Exit>()
.map(|e| e.0);
.downcast_ref::<wasmtime_wasi::I32Exit>()
.map(|e| e.0)
.or_else(|| {
e.downcast_ref::<wasmtime_wasi::preview2::I32Exit>()
.map(|e| e.0)
});
if let Some(exit_code) = wasi_exit_code {
debug!(
plugin = self.id.to_string(),
@@ -867,7 +881,21 @@ 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)
self.raw_call::<()>(&mut lock, name, data, None)
.map_err(|e| e.0)
.and_then(move |_| self.output())
}
pub fn call_with_arg<'a, 'b, T: ToBytes<'a>, U: FromBytes<'b>, V: 'static + Send + Sync>(
&'b mut self,
name: impl AsRef<str>,
input: T,
arg: V,
) -> Result<U, Error> {
let lock = self.instance.clone();
let mut lock = lock.lock().unwrap();
let data = input.to_bytes()?;
self.raw_call(&mut lock, name, data, Some(arg))
.map_err(|e| e.0)
.and_then(move |_| self.output())
}
@@ -886,7 +914,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)
self.raw_call::<()>(&mut lock, name, data, None)
.and_then(move |_| self.output().map_err(|e| (e, -1)))
}
@@ -995,7 +1023,7 @@ macro_rules! typed_plugin {
impl $name {
$(
pub fn $f<'a, $( $( $lt $( : $clt )? ),+ )? >(&'a mut self, input: $input) -> Result<$output, $crate::Error> {
self.0.call(stringify!($f), input)
self.0.call::<_, _>(stringify!($f), input)
}
)*
}

View File

@@ -389,6 +389,20 @@ pub unsafe extern "C" fn extism_plugin_config(
}
};
let wasi = &mut plugin.current_plugin_mut().wasi;
if let Some(Wasi { ctx, .. }) = wasi {
for (k, v) in json.iter() {
match v {
Some(v) => {
let _ = ctx.push_env(k, v);
}
None => {
let _ = ctx.push_env(k, "");
}
}
}
}
let id = plugin.id;
let config = &mut plugin.current_plugin_mut().manifest.config;
for (k, v) in json.into_iter() {
@@ -471,7 +485,7 @@ pub unsafe extern "C" fn 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);
let res = plugin.raw_call::<()>(&mut lock, name, input, None);
match res {
Err((e, rc)) => plugin.return_error(&mut lock, e, rc),