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: rollup to libextism 1.9.1 #32

Merged
merged 8 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
94 changes: 94 additions & 0 deletions src/CompiledPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

declare(strict_types=1);

namespace Extism;

/**
* A pre-compiled plugin ready to be instantiated.
*/
class CompiledPlugin
{
private \FFI\CData $handle;
private \Extism\Internal\LibExtism $lib;
private array $functions;

/**
* Compile a plugin from a Manifest.
*
* @param Manifest $manifest A manifest that describes the Wasm binaries
* @param array $functions Array of host functions
* @param bool $withWasi Enable WASI support
*/
public function __construct(Manifest $manifest, array $functions = [], bool $withWasi = false)
{
global $lib;

if ($lib === null) {
$lib = new \Extism\Internal\LibExtism();
}

$this->lib = $lib;
$this->functions = $functions;

$data = json_encode($manifest);
if (!$data) {
throw new \Extism\PluginLoadException("Failed to encode manifest");
}

$errPtr = $lib->ffi->new($lib->ffi->type("char*"));

$handle = $this->lib->extism_compiled_plugin_new(
$data,
strlen($data),
$functions,
count($functions),
$withWasi,
\FFI::addr($errPtr)
);

if (\FFI::isNull($errPtr) === false) {
$error = \FFI::string($errPtr);
$this->lib->extism_plugin_new_error_free($errPtr);
throw new \Extism\PluginLoadException("Extism: unable to compile plugin: " . $error);
}

$this->handle = $handle;
}

/**
* Instantiate a plugin from this compiled plugin.
*
* @return Plugin
*/
public function instantiate(): Plugin
{
return new Plugin($this);
}

/**
* Get the native handle
* @internal
*/
public function getNativeHandle(): \FFI\CData
{
return $this->handle;
}

/**
* Get the functions array
* @internal
*/
public function getFunctions(): array
{
return $this->functions;
}

/**
* Destructor to clean up resources
*/
public function __destruct()
{
$this->lib->extism_compiled_plugin_free($this->handle);
}
}
15 changes: 15 additions & 0 deletions src/CurrentPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ public function __construct($lib, \FFI\CData $handle)
$this->lib = $lib;
}

/**
* Get *a copy* of the current plugin call's associated host context data. Returns null if call was made without host context.
*
* @return mixed|null Returns a copy of the host context data or null if none was provided
*/
public function getCallHostContext()
{
$serialized = $this->lib->extism_current_plugin_host_context($this->handle);
if ($serialized === null) {
return null;
}

return unserialize($serialized);
}

/**
* Reads a string from the plugin's memory at the given offset.
*
Expand Down
136 changes: 136 additions & 0 deletions src/Internal/LibExtism.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,129 @@ public function extism_plugin_function_exists(\FFI\CData $plugin, string $func_n
return $this->ffi->extism_plugin_function_exists($plugin, $func_name);
}

/**
* Create a new plugin from an ExtismCompiledPlugin
*/
public function extism_plugin_new_from_compiled(\FFI\CData $compiled, \FFI\CData $errPtr): ?\FFI\CData
{
return $this->ffi->extism_plugin_new_from_compiled($compiled, $errPtr);
}

/**
* Create a new plugin with a fuel limit
*/
public function extism_plugin_new_with_fuel_limit(string $wasm, int $wasm_size, array $functions, int $n_functions, bool $with_wasi, int $fuel_limit, \FFI\CData $errPtr): ?\FFI\CData
{
$functionHandles = array_map(function ($function) {
return $function->handle;
}, $functions);

$functionHandles = $this->toCArray($functionHandles, "ExtismFunction*");

$ptr = $this->owned("uint8_t", $wasm);
$pluginPtr = $this->ffi->extism_plugin_new_with_fuel_limit($ptr, $wasm_size, $functionHandles, $n_functions, $with_wasi ? 1 : 0, $fuel_limit, $errPtr);
return $this->ffi->cast("ExtismPlugin*", $pluginPtr);
}

/**
* Get handle for plugin cancellation
*/
public function extism_plugin_cancel_handle(\FFI\CData $plugin): \FFI\CData
{
return $this->ffi->extism_plugin_cancel_handle($plugin);
}

/**
* Cancel a running plugin
*/
public function extism_plugin_cancel(\FFI\CData $handle): bool
{
return $this->ffi->extism_plugin_cancel($handle);
}

/**
* Pre-compile an Extism plugin
*/
public function extism_compiled_plugin_new(string $wasm, int $wasm_size, array $functions, int $n_functions, bool $with_wasi, \FFI\CData $errPtr): ?\FFI\CData
{
$functionHandles = array_map(function ($function) {
return $function->handle;
}, $functions);

$functionHandles = $this->toCArray($functionHandles, "ExtismFunction*");


$ptr = $this->owned("uint8_t", $wasm);
$pluginPtr = $this->ffi->extism_compiled_plugin_new($ptr, $wasm_size, $functionHandles, $n_functions, $with_wasi ? 1 : 0, $errPtr);
return $this->ffi->cast("ExtismCompiledPlugin*", $pluginPtr);
}

/**
* Free ExtismCompiledPlugin
*/
public function extism_compiled_plugin_free(\FFI\CData $plugin): void
{
$this->ffi->extism_compiled_plugin_free($plugin);
}

/**
* Enable HTTP response headers in plugins
*/
public function extism_plugin_allow_http_response_headers(\FFI\CData $plugin): void
{
$this->ffi->extism_plugin_allow_http_response_headers($plugin);
}

/**
* Get plugin's ID
*/
public function extism_plugin_id(\FFI\CData $plugin): \FFI\CData
{
return $this->ffi->extism_plugin_id($plugin);
}

/**
* Update plugin config
*/
public function extism_plugin_config(\FFI\CData $plugin, string $json, int $json_size): bool
{
$ptr = $this->owned("uint8_t", $json);
return $this->ffi->extism_plugin_config($plugin, $ptr, $json_size);
}

/**
* Call a function with host context
*/
public function extism_plugin_call_with_host_context(\FFI\CData $plugin, string $func_name, string $data, int $data_len, $host_context): int
{
$dataPtr = $this->owned("uint8_t", $data);

if ($host_context === null) {
return $this->ffi->extism_plugin_call_with_host_context($plugin, $func_name, $dataPtr, $data_len, null);
}

$serialized = serialize($host_context);
$contextPtr = $this->ffi->new("char*");
$contextArray = $this->ownedZero($serialized);
$contextPtr = \FFI::addr($contextArray);

return $this->ffi->extism_plugin_call_with_host_context(
$plugin,
$func_name,
$dataPtr,
$data_len,
$contextPtr
);
}

/**
* Reset plugin
*/
public function extism_plugin_reset(\FFI\CData $plugin): bool
{
return $this->ffi->extism_plugin_reset($plugin);
}

public function extism_version(): string
{
return $this->ffi->extism_version();
Expand All @@ -112,6 +235,19 @@ public function extism_plugin_call(\FFI\CData $plugin, string $func_name, string
return $this->ffi->extism_plugin_call($plugin, $func_name, $dataPtr, $data_len);
}

/**
* Get the current plugin's associated host context data
*/
public function extism_current_plugin_host_context(\FFI\CData $plugin): ?string
{
$ptr = $this->ffi->extism_current_plugin_host_context($plugin);
if ($ptr === null || \FFI::isNull($ptr)) {
return null;
}

return \FFI::string($this->ffi->cast("char *", $ptr));
}

public function extism_error(\FFI\CData $plugin): ?string
{
return $this->ffi->extism_error($plugin);
Expand Down
40 changes: 39 additions & 1 deletion src/Internal/extism.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ typedef enum {
*/
typedef struct ExtismCancelHandle ExtismCancelHandle;

typedef struct ExtismCompiledPlugin ExtismCompiledPlugin;

/**
* CurrentPlugin stores data that is available to the caller in PDK functions, this should
* only be accessed from inside a host function
Expand Down Expand Up @@ -176,6 +178,21 @@ void extism_function_free(ExtismFunction *f);
*/
void extism_function_set_namespace(ExtismFunction *ptr, const char *namespace_);

/**
* Pre-compile an Extism plugin
*/
ExtismCompiledPlugin *extism_compiled_plugin_new(const uint8_t *wasm,
ExtismSize wasm_size,
const ExtismFunction **functions,
ExtismSize n_functions,
bool with_wasi,
char **errmsg);

/**
* Free `ExtismCompiledPlugin`
*/
void extism_compiled_plugin_free(ExtismCompiledPlugin *plugin);

/**
* Create a new plugin with host functions, the functions passed to this function no longer need to be manually freed using
*
Expand All @@ -192,13 +209,34 @@ ExtismPlugin *extism_plugin_new(const uint8_t *wasm,
bool with_wasi,
char **errmsg);

/**
* Create a new plugin from an `ExtismCompiledPlugin`
*/
ExtismPlugin *extism_plugin_new_from_compiled(const ExtismCompiledPlugin *compiled, char **errmsg);

/**
* Create a new plugin and set the number of instructions a plugin is allowed to execute
*/
ExtismPlugin *extism_plugin_new_with_fuel_limit(const uint8_t *wasm,
ExtismSize wasm_size,
const ExtismFunction **functions,
ExtismSize n_functions,
bool with_wasi,
uint64_t fuel_limit,
char **errmsg);

/**
* Enable HTTP response headers in plugins using `extism:host/env::http_request`
*/
void extism_plugin_allow_http_response_headers(ExtismPlugin *plugin);

/**
* Free the error returned by `extism_plugin_new`, errors returned from `extism_plugin_error` don't need to be freed
*/
void extism_plugin_new_error_free(char *err);

/**
* Remove a plugin from the registry and free associated memory
* Free `ExtismPlugin`
*/
void extism_plugin_free(ExtismPlugin *plugin);

Expand Down
Loading
Loading