From d284a8733d2efb0ad593de2e964329ad33163f04 Mon Sep 17 00:00:00 2001 From: Muhammad Azeez Date: Thu, 12 Dec 2024 17:09:51 +0300 Subject: [PATCH] call with host context --- src/CurrentPlugin.php | 15 +++++++++++++++ src/Internal/LibExtism.php | 31 ++++++++++++++++++++++++++++++- tests/PluginTest.php | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/CurrentPlugin.php b/src/CurrentPlugin.php index e931a55..64c0ff9 100644 --- a/src/CurrentPlugin.php +++ b/src/CurrentPlugin.php @@ -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. * diff --git a/src/Internal/LibExtism.php b/src/Internal/LibExtism.php index aca82f9..5c267fb 100644 --- a/src/Internal/LibExtism.php +++ b/src/Internal/LibExtism.php @@ -197,7 +197,23 @@ public function extism_plugin_config(\FFI\CData $plugin, string $json, int $json 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); - return $this->ffi->extism_plugin_call_with_host_context($plugin, $func_name, $dataPtr, $data_len, $host_context); + + 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 + ); } /** @@ -219,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); diff --git a/tests/PluginTest.php b/tests/PluginTest.php index 5a21e42..c86bc77 100644 --- a/tests/PluginTest.php +++ b/tests/PluginTest.php @@ -98,6 +98,39 @@ public function testHostFunctions(): void $this->assertEquals('{"count":3,"total":6,"vowels":"aeiouAEIOU"}', $response); } + + public function testCallWithHostContext(): void + { + $multiUserKvStore = [[]]; + + $kvRead = new HostFunction("kv_read", [ExtismValType::I64], [ExtismValType::I64], function (CurrentPlugin $p, string $key) use (&$multiUserKvStore) { + $ctx = $p->getCallHostContext(); // get a copy of the host context data + $userId = $ctx["userId"]; + $kvStore = $multiUserKvStore[$userId] ?? []; + + return $kvStore[$key] ?? "\0\0\0\0"; + }); + + $kvWrite = new HostFunction("kv_write", [ExtismValType::I64, ExtismValType::I64], [], function (CurrentPlugin $p, string $key, string $value) use (&$multiUserKvStore) { + $ctx = $p->getCallHostContext(); // get a copy of the host context data + $userId = $ctx["userId"]; + $kvStore = $multiUserKvStore[$userId] ?? []; + + $kvStore[$key] = $value; + $multiUserKvStore[$userId] = $kvStore; + }); + + $plugin = self::loadPlugin("count_vowels_kvstore.wasm", [$kvRead, $kvWrite]); + + $ctx = ["userId" => 1]; + + $response = $plugin->callWithContext("count_vowels", "Hello World!", $ctx); + $this->assertEquals('{"count":3,"total":3,"vowels":"aeiouAEIOU"}', $response); + + $response = $plugin->callWithContext("count_vowels", "Hello World!", $ctx); + $this->assertEquals('{"count":3,"total":6,"vowels":"aeiouAEIOU"}', $response); + } + public function testHostFunctionManual(): void { $kvstore = [];