Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: libextism rollup host context, fuel, http response, compiled plugin #2

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Extism/lib/Extism.pm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use 5.016;
use strict;
use warnings;
use Extism::XS qw(version log_file);
use Extism::CompiledPlugin;
use Extism::Plugin;
use Extism::Function ':all';
use Exporter 'import';
Expand Down
58 changes: 58 additions & 0 deletions Extism/lib/Extism/CompiledPlugin.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package Extism::CompiledPlugin;

use 5.016;
use strict;
use warnings;
use Carp qw(croak);
use Extism::XS qw(
compiled_plugin_new
compiled_plugin_free
);
use Exporter 'import';
use Data::Dumper qw(Dumper);
use Devel::Peek qw(Dump);
use version 0.77;
our $VERSION = qv(v0.2.0);

our @EXPORT_OK = qw(BuildPluginNewParams);

sub BuildPluginNewParams {
my ($wasm, $opt) = @_;
my $functions = $opt->{functions} // [];
my @rawfunctions = map {$$_} @{$functions};
my %p = (
wasm => $wasm,
_functions_array => pack('Q*', @rawfunctions)
);
$p{functions} = unpack('Q', pack('P', $p{_functions_array}));
$p{n_functions} = scalar(@rawfunctions);
$p{wasi} = $opt->{wasi} // 0;
$p{fuel_limit} = $opt->{fuel_limit};
$p{errptr} = "\x00" x 8;
$p{errmsg} = unpack('Q', pack('P', $p{errptr}));
\%p
}

sub new {
my ($name, $wasm, $options) = @_;
my %opt = %{$options // {}};
if (defined $opt{fuel_limit}) {
croak "No way to set fuel for CompiledPlugins yet";
}
my $p = BuildPluginNewParams($wasm, \%opt);
my $compiled = compiled_plugin_new($p->{wasm}, length($p->{wasm}), $p->{functions}, $p->{n_functions}, $p->{wasi}, $p->{errmsg});
my %savedoptions;
if ($opt{allow_http_response_headers}) {
$savedoptions{allow_http_response_headers} = $opt{allow_http_response_headers};
}
my %obj = ( compiled => $compiled, options => \%savedoptions);
bless \%obj, $name
}

sub DESTROY {
my ($self) = @_;
$self->{compiled} or return;
compiled_plugin_free($self->{compiled});
}

1;
5 changes: 5 additions & 0 deletions Extism/lib/Extism/CurrentPlugin.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use Extism::XS qw(current_plugin_memory
current_plugin_memory_alloc
current_plugin_memory_length
current_plugin_memory_free
current_plugin_host_context
CopyToPtr);

use version 0.77;
Expand Down Expand Up @@ -53,4 +54,8 @@ sub memory_alloc_and_store {
return $ptr;
}

sub host_context {
current_plugin_host_context($Extism::CurrentPlugin::instance)
}

1; # End of Extism::CurrentPlugin
39 changes: 22 additions & 17 deletions Extism/lib/Extism/Plugin.pm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use warnings;
use Carp qw(croak);
use Extism::XS qw(
plugin_new
plugin_new_with_fuel_limit
plugin_new_from_compiled
plugin_allow_http_response_headers
plugin_new_error_free
plugin_call
plugin_error
Expand All @@ -20,6 +23,7 @@ use Extism::XS qw(
);
use Extism::Plugin::CallException;
use Extism::Plugin::CancelHandle;
use Extism::CompiledPlugin qw(BuildPluginNewParams);
use Data::Dumper qw(Dumper);
use Devel::Peek qw(Dump);
use JSON::PP qw(encode_json);
Expand All @@ -29,27 +33,28 @@ our $VERSION = qv(v0.2.0);

sub new {
my ($name, $wasm, $options) = @_;
my $functions = [];
my $with_wasi = 0;
if ($options) {
if (exists $options->{functions}) {
$functions = $options->{functions};
}
if (exists $options->{wasi}) {
$with_wasi = $options->{wasi};
}
my ($plugin, $opt, $errptr);
if (!ref($wasm) || !$wasm->isa('Extism::CompiledPlugin')) {
$opt = defined $options ? {%$options} : {};
my $p = BuildPluginNewParams($wasm, $opt);
$plugin = ! defined $p->{fuel_limit}
? plugin_new($p->{wasm}, length($p->{wasm}), $p->{functions}, $p->{n_functions}, $p->{wasi}, $p->{errmsg})
: plugin_new_with_fuel_limit($p->{wasm}, length($p->{wasm}), $p->{functions}, $p->{n_functions}, $p->{wasi}, $p->{fuel_limit}, $p->{errmsg});
$errptr = $p->{errptr};
} else {
$opt = $wasm->{options};
$errptr = "\x00" x 8;
my $errmsg = unpack('Q', pack('P', $errptr));
$plugin = plugin_new_from_compiled($wasm->{compiled}, $errmsg);
}
my $errptr = "\x00" x 8;
my $errptrptr = unpack('Q', pack('P', $errptr));
my @rawfunctions = map {$$_} @{$functions};
my $functionsarray = pack('Q*', @rawfunctions);
my $functionsptr = unpack('Q', pack('P', $functionsarray));
my $plugin = plugin_new($wasm, length($wasm), $functionsptr, scalar(@rawfunctions), $with_wasi, $errptrptr);
if (! $plugin) {
my $errmsg = unpack('p', $errptr);
plugin_new_error_free(unpack('Q', $errptr));
croak $errmsg;
}
if ($opt->{allow_http_response_headers}) {
plugin_allow_http_response_headers($plugin);
}
bless \$plugin, $name
}

Expand All @@ -59,14 +64,14 @@ sub new {
# passed to the plugin. If INPUT is a reference, the referenced item will be
# encoded with json and then passed to the plugin.
sub call {
my ($self, $func_name, $input) = @_;
my ($self, $func_name, $input, $host_context) = @_;
$input //= '';
my $type = reftype($input);
if ($type) {
$input = $$input if($type eq 'SCALAR');
$input = encode_json($input);
}
my $rc = plugin_call($$self, $func_name, $input, length($input));
my $rc = plugin_call($$self, $func_name, $input, length($input), $host_context);
if ($rc != 0) {
die Extism::Plugin::CallException->new($rc, plugin_error($$self));
}
Expand Down
6 changes: 6 additions & 0 deletions Extism/lib/Extism/XS.pm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ XSLoader::load('Extism::XS', $VERSION);
our @EXPORT_OK = qw(
version
plugin_new
plugin_new_with_fuel_limit
plugin_allow_http_response_headers
plugin_new_error_free
plugin_call
plugin_error
Expand All @@ -33,9 +35,13 @@ our @EXPORT_OK = qw(
current_plugin_memory_alloc
current_plugin_memory_length
current_plugin_memory_free
current_plugin_host_context
log_file
log_custom
log_drain
compiled_plugin_new
compiled_plugin_free
plugin_new_from_compiled
CopyToPtr
);

Expand Down
69 changes: 66 additions & 3 deletions Extism/lib/Extism/XS.xs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ ExtismCurrentPlugin * T_PTR
ExtismMemoryHandle T_UV
const ExtismCancelHandle * T_PTR
PV T_PV
uint64_t T_UV
ExtismCompiledPlugin * T_PTR
const ExtismCompiledPlugin * T_PTR
HERE

const char *
Expand All @@ -89,6 +92,34 @@ version()
OUTPUT:
RETVAL

ExtismCompiledPlugin *
compiled_plugin_new(wasm, wasm_size, functions, n_functions, with_wasi, errmsg)
const uint8_t *wasm
ExtismSize wasm_size
const ExtismFunction **functions
ExtismSize n_functions
bool with_wasi
char **errmsg
CODE:
RETVAL = extism_compiled_plugin_new(wasm, wasm_size, functions, n_functions, with_wasi, errmsg);
OUTPUT:
RETVAL

void
compiled_plugin_free(compiled_plugin)
ExtismCompiledPlugin *compiled_plugin
CODE:
extism_compiled_plugin_free(compiled_plugin);

ExtismPlugin *
plugin_new_from_compiled(compiled_plugin, errmsg)
const ExtismCompiledPlugin *compiled_plugin
char **errmsg
CODE:
RETVAL = extism_plugin_new_from_compiled(compiled_plugin, errmsg);
OUTPUT:
RETVAL

ExtismPlugin *
plugin_new(wasm, wasm_size, functions, n_functions, with_wasi, errmsg)
const uint8_t *wasm
Expand All @@ -102,20 +133,41 @@ plugin_new(wasm, wasm_size, functions, n_functions, with_wasi, errmsg)
OUTPUT:
RETVAL

ExtismPlugin *
plugin_new_with_fuel_limit(wasm, wasm_size, functions, n_functions, with_wasi, fuel_limit, errmsg)
const uint8_t *wasm
ExtismSize wasm_size
const ExtismFunction **functions
ExtismSize n_functions
bool with_wasi
uint64_t fuel_limit
char **errmsg
CODE:
RETVAL = extism_plugin_new_with_fuel_limit(wasm, wasm_size, functions, n_functions, with_wasi, fuel_limit, errmsg);
OUTPUT:
RETVAL

void
plugin_new_error_free(err);
plugin_allow_http_response_headers(plugin)
ExtismPlugin *plugin
CODE:
extism_plugin_allow_http_response_headers(plugin);

void
plugin_new_error_free(err)
void *err
CODE:
extism_plugin_new_error_free(err);

int32_t
plugin_call(plugin, func_name, data, data_len)
plugin_call(plugin, func_name, data, data_len, host_context=&PL_sv_undef)
ExtismPlugin *plugin
const char *func_name
const uint8_t *data
ExtismSize data_len
SV *host_context
CODE:
RETVAL = extism_plugin_call(plugin, func_name, data, data_len);
RETVAL = extism_plugin_call_with_host_context(plugin, func_name, data, data_len, host_context);
OUTPUT:
RETVAL

Expand Down Expand Up @@ -261,6 +313,17 @@ current_plugin_memory_free(plugin, handle)
CODE:
extism_current_plugin_memory_free(plugin, handle);

SV *
current_plugin_host_context(plugin)
ExtismCurrentPlugin *plugin
CODE:
RETVAL = extism_current_plugin_host_context(plugin);
if (RETVAL != &PL_sv_undef) {
SvREFCNT_inc_simple_NN(RETVAL);
}
OUTPUT:
RETVAL

void
log_file(filename, log_level)
const char *filename
Expand Down
67 changes: 66 additions & 1 deletion Extism/t/02-extism.t
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use Extism ':all';
use JSON::PP qw(encode_json decode_json);
use File::Temp qw(tempfile);
use Devel::Peek qw(Dump);
plan tests => 45;
plan tests => 54;

# ...
ok(Extism::version());
Expand Down Expand Up @@ -213,3 +213,68 @@ eval {
ok($@);
ok($@->{code} != 0);
ok($@->{message});

# Test host_context
{
my $voidfunction = Extism::Function->new("hello_void", [], [], sub {
ok(! defined Extism::CurrentPlugin::host_context);
return;
});
my $paramsfunction = Extism::Function->new("hello_params", [Extism_F64, Extism_I32, Extism_F32, Extism_I64], [Extism_I64], sub {
# not called
});
my $fplugin = Extism::Plugin->new($hostwasm, {functions => [$voidfunction, $paramsfunction], wasi => 1});
$fplugin->call('call_hello_void');
}
{
my %context = ( abc => 123);
my $voidfunction = Extism::Function->new("hello_void", [], [], sub {
my $ctx = Extism::CurrentPlugin::host_context;
is_deeply($ctx, \%context);
ok($ctx == \%context);
return;
});
my $paramsfunction = Extism::Function->new("hello_params", [Extism_F64, Extism_I32, Extism_F32, Extism_I64], [Extism_I64], sub {
# not called
});
my $fplugin = Extism::Plugin->new($hostwasm, {functions => [$voidfunction, $paramsfunction], wasi => 1});
$fplugin->call('call_hello_void', '', \%context);
}

# fuel
{
my $plugin = Extism::Plugin->new($wasm, {wasi => 1, fuel_limit => 100000});
my $output = $plugin->call('count_vowels', "this is a test");
my $outputhash = decode_json($output);
ok($outputhash->{count} == 4);
}
{
my $plugin = Extism::Plugin->new($wasm, {wasi => 1, fuel_limit => 5});
eval {
my $output = $plugin->call('count_vowels', "this is a test");
};
ok($@);
}

# http headers
{
my $plugin = Extism::Plugin->new($wasm, {wasi => 1, allow_http_response_headers => 1});
ok($plugin);
}

# compiled plugin
{
my $compiled = Extism::CompiledPlugin->new($wasm, {wasi => 1});
for (1..2) {
my $plugin = Extism::Plugin->new($compiled);
my $output = $plugin->call('count_vowels', "this is a test");
my $outputhash = decode_json($output);
ok($outputhash->{count} == 4);
}
}
{
eval {
Extism::CompiledPlugin->new($wasm, {wasi => 1, fuel_limit => 20});
};
ok($@);
}
Loading