Compare commits

...

15 Commits

Author SHA1 Message Date
zach
3ecc9c0dac ci: re-organize release workflow 2025-01-21 15:51:29 -08:00
zach
f57d987d48 ci: fix android release, attempt #2 (#818) 2025-01-21 12:08:18 -08:00
zach
9da6d43f05 ci: install android libunwind before build step (#817)
Fixes #816
2025-01-21 11:41:10 -08:00
zach
d1a248e19e cleanup: stop timer from using 100% cpu when no timeouts are set (#814)
Fixes an issue reported on discord
(https://discord.com/channels/1011124058408112148/1154513155209298041/1329622656235864156)
where the timer thread is taking up an entire CPU
2025-01-20 14:01:37 -08:00
dependabot[bot]
7b2db7588b chore(deps): Update cbindgen requirement from 0.27 to 0.28 (#815)
Updates the requirements on
[cbindgen](https://github.com/mozilla/cbindgen) to permit the latest
version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/mozilla/cbindgen/releases">cbindgen's
releases</a>.</em></p>
<blockquote>
<h1>0.28.0</h1>
<ul>
<li>Parse unsafe attributes in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1020">mozilla/cbindgen#1020</a></li>
<li>Fix local override of enum prefix-with-name by jsgf in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1006">mozilla/cbindgen#1006</a></li>
<li>Add rename-all=prefix in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1021">mozilla/cbindgen#1021</a></li>
<li>ir: add support for UnsafeCell and SyncUnsafeCell by alekitto in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1003">mozilla/cbindgen#1003</a></li>
<li>Implement mangling for arrays in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1022">mozilla/cbindgen#1022</a></li>
<li>Fix: Ignore <code>CARGO_BUILD_TARGET</code> in tests by bryango in
<a
href="https://redirect.github.com/mozilla/cbindgen/pull/1010">mozilla/cbindgen#1010</a></li>
<li>Newline for each field for constexpr field constants by youknowone
in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/988">mozilla/cbindgen#988</a></li>
<li>Fix clippy warnings by youknowone in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1026">mozilla/cbindgen#1026</a></li>
<li>Add aarch64/arm64 to CI by NickeZ in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1036">mozilla/cbindgen#1036</a></li>
<li>Add <code>unstable_ir</code> feature flag that makes the ir pub by
heesooy in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/1011">mozilla/cbindgen#1011</a></li>
<li>Support generated a symbols file by TheElectronWill in <a
href="https://redirect.github.com/mozilla/cbindgen/pull/916">mozilla/cbindgen#916</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/mozilla/cbindgen/blob/master/CHANGES">cbindgen's
changelog</a>.</em></p>
<blockquote>
<h1>0.28.0</h1>
<pre><code> * Parse unsafe attributes in
https://github.com/mozilla/cbindgen/pull/1020
* Fix local override of enum prefix-with-name by jsgf in
https://github.com/mozilla/cbindgen/pull/1006
* Add rename-all=prefix in https://github.com/mozilla/cbindgen/pull/1021
* ir: add support for UnsafeCell and SyncUnsafeCell by alekitto in
https://github.com/mozilla/cbindgen/pull/1003
* Implement mangling for arrays in
https://github.com/mozilla/cbindgen/pull/1022
* Fix: Ignore `CARGO_BUILD_TARGET` in tests by bryango in
https://github.com/mozilla/cbindgen/pull/1010
* Newline for each field for constexpr field constants by youknowone in
https://github.com/mozilla/cbindgen/pull/988
* Fix clippy warnings by youknowone in
https://github.com/mozilla/cbindgen/pull/1026
* Add aarch64/arm64 to CI by NickeZ in
https://github.com/mozilla/cbindgen/pull/1036
* Add `unstable_ir` feature flag that makes the ir pub by heesooy in
https://github.com/mozilla/cbindgen/pull/1011
* Support generated a symbols file by TheElectronWill in
https://github.com/mozilla/cbindgen/pull/916
</code></pre>
<h1>0.27.0</h1>
<pre><code>  * Revert: The `Config` struct now has a private member.
* Allow users to specify a crate version for bindings generation
([#901](https://github.com/mozilla/cbindgen/issues/901)).
* Update MSRV to 1.74
([#912](https://github.com/mozilla/cbindgen/issues/912),
[#987](https://github.com/mozilla/cbindgen/issues/987)).
* Support #[deprecated] on enum variants
([#933](https://github.com/mozilla/cbindgen/issues/933)).
* Support integrating the package_version information in a header file
comment ([#939](https://github.com/mozilla/cbindgen/issues/939)).
* Add a language backend
([#942](https://github.com/mozilla/cbindgen/issues/942)).
* Support generics with defaulted args
([#959](https://github.com/mozilla/cbindgen/issues/959)).
* Add `VaList` compatibility
([#970](https://github.com/mozilla/cbindgen/issues/970)).
</code></pre>
<h1>0.26.0</h1>
<pre><code>  * Fix swapping of `&gt;&gt;=` and `&lt;&lt;=` in constants.
* Add support for #[deprecated]
([#860](https://github.com/mozilla/cbindgen/issues/860)).
  * Built-in support for bitflags 2.0.
  * Support for &quot;C-unwind&quot; ABI.
* Generate bindings for non-public extern items if they are
#[no_mangle].
</code></pre>
<h2>0.25.0</h2>
<pre><code>  * Re-release of yanked 0.24.6 as a major release
  * Update MSRV to 1.57
* Support variadic arguments (`...`)
([#805](https://github.com/mozilla/cbindgen/issues/805))
* Add --depfile option
([#820](https://github.com/mozilla/cbindgen/issues/820))
  * Breaking changes: The `Config` struct now has a private member.
</code></pre>
<h2>0.24.6 (YANKED: depfile option was breaking, see <a
href="https://redirect.github.com/mozilla/cbindgen/issues/841">#841</a>)</h2>
<pre><code>  * Update MSRV to 1.57
* Support variadic arguments (`...`)
([#805](https://github.com/mozilla/cbindgen/issues/805))
* Add --depfile option
([#820](https://github.com/mozilla/cbindgen/issues/820))
</code></pre>
<h2>0.24.5</h2>
<pre><code>  * Don't enforce tempfile version.
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bd78bbe59b"><code>bd78bbe</code></a>
Release 0.28.0</li>
<li><a
href="8ca9c4c20f"><code>8ca9c4c</code></a>
tests: Fix symbol file and tests.</li>
<li><a
href="152f91dee0"><code>152f91d</code></a>
Appease clippy.</li>
<li><a
href="70b9d7a980"><code>70b9d7a</code></a>
tests: Run rustfmt.</li>
<li><a
href="87afbf9e01"><code>87afbf9</code></a>
Add a way to generate a list of symbols for dynamic linkage, resolves <a
href="https://redirect.github.com/mozilla/cbindgen/issues/907">#907</a></li>
<li><a
href="80c50c643a"><code>80c50c6</code></a>
Add <code>unstable_ir</code> feature flag that makes the ir pub</li>
<li><a
href="e82815e99a"><code>e82815e</code></a>
Refactor arm64 build to matrix strategy</li>
<li><a
href="a5e1443a45"><code>a5e1443</code></a>
Add aarch64/arm64 to CI</li>
<li><a
href="b9b8f8878a"><code>b9b8f88</code></a>
Fix clippy warnings</li>
<li><a
href="89a9faa97c"><code>89a9faa</code></a>
newlines for constexpr</li>
<li>Additional commits viewable in <a
href="https://github.com/mozilla/cbindgen/compare/v0.27.0...0.28.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 14:01:02 -08:00
Benjamin Eckel
a367bc77a3 Add Android targets (#812)
Closes #811

Keep in mind that these targets seem to be tier 3 support and not quite
stable, but i think it's fine to open for experimenting:
https://docs.wasmtime.dev/stability-tiers.html
2025-01-14 10:23:59 -08:00
pwnintended
98800fe8a0 feat: added a function to track fuel consumption (#807)
This PR adds a function to get the fuel consumed by a plugin. This is
useful for systems that want to fairly balance compute. It's my first
time doing anything in rust so let me know if something needs
improvements!

---------

Co-authored-by: zach <zach@dylibso.com>
2024-12-16 16:04:05 -08:00
zach
7e3665ae8c fix: improve sdk error messages around imports (#806)
Closes https://github.com/extism/extism/issues/801


Updates the error from:

```
Unable to compile Extism plugin: incompatible import type for `extism:host/user::wrong_type`
```

to:

```
Unable to compile Extism plugin: types incompatible: expected type `(func (result i32))`, found type `(func (result i64))`
```
2024-12-13 11:45:24 -08:00
Muhammad Azeez
3cfde7966d Trigger NuGet package publishing when a new release is published (#805)
This makes sure the latest releases are always available on NuGet too
2024-12-05 19:44:33 +03:00
zach
5d18cc71eb chore: fix clippy (#799) 2024-12-02 16:46:48 -08:00
Miles Johnson
4f599d4b20 Change function_exists to &self (#796)
I wrap the `Plugin` instance in a `RwLock` and because `function_exists`
requires `&mut self`, I have to acquire a write lock everytime to just
check if a function exists, which causes lock contention.

This changes it to `&self` since it doesn't need to mutate.
2024-12-02 09:46:38 -08:00
Chris Dickinson
4db57de98e fix: remove unwrap() from extism_compiled_plugin_new
`extism_compiled_plugin_new` would panic on bad manifest input (there's
a test in the python sdk [1] that hits this directly.) Catch the error and
set `errmsg` appropriately instead.

Additionally: golf the function pointer casting for the various `plugin_new` calls,
with the goal of reducing the number of allocations by leaning on iterator size
hints (and reducing the scope of `unsafe{}` use.) This part can be severed: it
introduces a breaking change. Previously `NULL` values were silently accepted in
the `functions**` list; now they fail. This maintains consistency with behavior on
"consumed" `ExtismFunction` pointer.

[1]: https://github.com/extism/python-sdk/blob/main/tests/test_extism.py#L50-L53
2024-11-25 13:16:00 -08:00
zach
9134635b37 cleanup: return better errors for wasi command modules (#793) 2024-11-25 08:49:57 -08:00
dependabot[bot]
75428f26e2 chore(deps): Bump dawidd6/action-download-artifact from 2 to 6 in /.github/workflows (#792)
Bumps
[dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact)
from 2 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dawidd6/action-download-artifact/releases">dawidd6/action-download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v6</h2>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v5...v6">https://github.com/dawidd6/action-download-artifact/compare/v5...v6</a></p>
<h2>v5</h2>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v4...v5">https://github.com/dawidd6/action-download-artifact/compare/v4...v5</a></p>
<h2>v4</h2>
<h2>What's Changed</h2>
<ul>
<li><strong>VERSIONING CHANGE</strong>: now there will only be major
releases of this action, e.g. v5, v6 and so on</li>
<li>build(deps): bump undici from 5.28.3 to 5.28.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/284">dawidd6/action-download-artifact#284</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.4 to
2.1.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/285">dawidd6/action-download-artifact#285</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.5 to
2.1.7 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/287">dawidd6/action-download-artifact#287</a></li>
<li>build(deps): bump adm-zip from 0.5.12 to 0.5.13 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/289">dawidd6/action-download-artifact#289</a></li>
<li>Set allow_forks to false by default by <a
href="https://github.com/timweri"><code>@​timweri</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/290">dawidd6/action-download-artifact#290</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/timweri"><code>@​timweri</code></a> made
their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/290">dawidd6/action-download-artifact#290</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3...v4">https://github.com/dawidd6/action-download-artifact/compare/v3...v4</a></p>
<h2>v3.1.4</h2>
<h2>What's Changed</h2>
<ul>
<li>build(deps): bump adm-zip from 0.5.10 to 0.5.12 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/282">dawidd6/action-download-artifact#282</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.2 to
2.1.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/280">dawidd6/action-download-artifact#280</a></li>
<li>fix: accept expired artifacts with documentation url by <a
href="https://github.com/wdconinc"><code>@​wdconinc</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/283">dawidd6/action-download-artifact#283</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/wdconinc"><code>@​wdconinc</code></a>
made their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/283">dawidd6/action-download-artifact#283</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3...v3.1.4">https://github.com/dawidd6/action-download-artifact/compare/v3...v3.1.4</a></p>
<h2>v3.1.3</h2>
<h2>What's Changed</h2>
<ul>
<li>node_modules: upgrade by <a
href="https://github.com/dawidd6"><code>@​dawidd6</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/276">dawidd6/action-download-artifact#276</a></li>
<li>build(deps): bump <code>@​actions/artifact</code> from 2.1.1 to
2.1.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/277">dawidd6/action-download-artifact#277</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3.1.2...v3.1.3">https://github.com/dawidd6/action-download-artifact/compare/v3.1.2...v3.1.3</a></p>
<h2>v3.1.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Read workflow_search input as a boolean by <a
href="https://github.com/klutchell"><code>@​klutchell</code></a> in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/273">dawidd6/action-download-artifact#273</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/klutchell"><code>@​klutchell</code></a>
made their first contribution in <a
href="https://redirect.github.com/dawidd6/action-download-artifact/pull/273">dawidd6/action-download-artifact#273</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/dawidd6/action-download-artifact/compare/v3.1.1...v3.1.2">https://github.com/dawidd6/action-download-artifact/compare/v3.1.1...v3.1.2</a></p>
<h2>v3.1.1</h2>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bf251b5aa9"><code>bf251b5</code></a>
node_modules: upgrade</li>
<li><a
href="93c6296611"><code>93c6296</code></a>
README: v5</li>
<li><a
href="deb3bb8325"><code>deb3bb8</code></a>
node_modules: upgrade</li>
<li><a
href="1d93f37db2"><code>1d93f37</code></a>
README: v4</li>
<li><a
href="854e2de939"><code>854e2de</code></a>
Set allow_forks to false by default (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/290">#290</a>)</li>
<li><a
href="436c9d3774"><code>436c9d3</code></a>
build(deps): bump adm-zip from 0.5.12 to 0.5.13 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/289">#289</a>)</li>
<li><a
href="14040524bb"><code>1404052</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.5 to 2.1.7
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/287">#287</a>)</li>
<li><a
href="8a9be734dc"><code>8a9be73</code></a>
build(deps): bump <code>@​actions/artifact</code> from 2.1.4 to 2.1.5
(<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/285">#285</a>)</li>
<li><a
href="df593bbd04"><code>df593bb</code></a>
build(deps): bump undici from 5.28.3 to 5.28.4 (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/284">#284</a>)</li>
<li><a
href="09f2f74827"><code>09f2f74</code></a>
fix: accept expired artifacts with documentation url (<a
href="https://redirect.github.com/dawidd6/action-download-artifact/issues/283">#283</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/dawidd6/action-download-artifact/compare/v2...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dawidd6/action-download-artifact&package-manager=github_actions&previous-version=2&new-version=6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/extism/extism/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-25 07:50:29 -08:00
Steve Manuel
7beeee35f1 feat: add overview on generating bindings (#789)
Primarily adds the Generating Bindings section, but also updates the PDK
and SDK list to include more languages.
2024-11-19 22:48:00 -08:00
13 changed files with 376 additions and 135 deletions

View File

@@ -1,4 +1,6 @@
on:
release:
types: [published, edited]
workflow_dispatch:
name: Release .NET Native NuGet Packages
@@ -18,7 +20,7 @@ jobs:
uses: actions/setup-dotnet@v3.0.3
with:
dotnet-version: 7.x
- uses: dawidd6/action-download-artifact@v2
- uses: dawidd6/action-download-artifact@v6
with:
workflow: release.yml
name: release-artifacts

View File

@@ -38,6 +38,20 @@ jobs:
static-dll-artifact: ''
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'ubuntu'
target: 'aarch64-linux-android'
artifact: 'libextism.so'
static-artifact: 'libextism.a'
static-dll-artifact: ''
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'ubuntu'
target: 'x86_64-linux-android'
artifact: 'libextism.so'
static-artifact: 'libextism.a'
static-dll-artifact: ''
pc-in: 'extism.pc.in'
static-pc-in: 'extism-static.pc.in'
- os: 'ubuntu'
target: 'aarch64-unknown-linux-gnu'
artifact: 'libextism.so'
@@ -98,13 +112,11 @@ jobs:
pyproject="$(cat extism-maturin/pyproject.toml)"
<<<"$pyproject" >extism-maturin/pyproject.toml sed -e 's/^version = "0.0.0.replaced-by-ci"/version = "'"$version"'"/g'
- name: Install Rust
uses: actions-rs/toolchain@v1
- uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
target: ${{ matrix.target }}
override: true
toolchain: stable
- uses: Swatinem/rust-cache@v2
with:
@@ -113,11 +125,15 @@ jobs:
cache-on-failure: "true"
- name: Build Target (${{ matrix.os }} ${{ matrix.target }})
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.os != 'windows' }}
command: build
args: --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}
if: ${{ matrix.os != 'windows' }}
run: |
cargo install cross
cross build --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}
- name: Build Target (${{ matrix.os }} ${{ matrix.target }})
if: ${{ matrix.os == 'windows' }}
run: |
cargo build --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}
- uses: actions/setup-python@v4
with:

View File

@@ -61,11 +61,11 @@ started:
# Compile WebAssembly to run in Extism Hosts
Extism Hosts (running the SDK) must execute WebAssembly code that has a [PDK, or Plug-in Development Kit](https://extism.org/docs/concepts/pdk),
library compiled in to the `.wasm` binary. PDKs make it easy for plug-in /
extension code authors to read input from the host and return data back, read
provided configuration, set/get variables, make outbound HTTP calls if allowed,
and more.
Extism Hosts (running the SDK) must execute WebAssembly code that has a
[PDK, or Plug-in Development Kit](https://extism.org/docs/concepts/pdk), library
compiled in to the `.wasm` binary. PDKs make it easy for plug-in / extension
code authors to read input from the host and return data back, read provided
configuration, set/get variables, make outbound HTTP calls if allowed, and more.
Pick a PDK to import into your Wasm program, and refer to the documentation to
get started:
@@ -74,13 +74,73 @@ get started:
| ------------------ | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------- |
| Rust PDK | <img alt="Rust PDK" src="https://extism.org/img/sdk-languages/rust.svg" width="50px"/> | https://github.com/extism/rust-pdk | [Crates.io](https://crates.io/crates/extism-pdk) |
| JS PDK | <img alt="JS PDK" src="https://extism.org/img/sdk-languages/js.svg" width="50px"/> | https://github.com/extism/js-pdk | N/A |
| Python PDK | <img alt="Python PDK" src="https://extism.org/img/sdk-languages/python.svg" width="50px"/> | https://github.com/extism/python-pdk | N/A |
| Go PDK | <img alt="Go PDK" src="https://extism.org/img/sdk-languages/go.svg" width="50px"/> | https://github.com/extism/go-pdk | [Go mod](https://pkg.go.dev/github.com/extism/go-pdk) |
| Haskell PDK | <img alt="Haskell PDK" src="https://extism.org/img/sdk-languages/haskell.svg" width="50px"/> | https://github.com/extism/haskell-pdk | [Hackage](https://hackage.haskell.org/package/extism-pdk) |
| AssemblyScript PDK | <img alt="AssemblyScript PDK" src="https://extism.org/img/sdk-languages/assemblyscript.svg" width="50px"/> | https://github.com/extism/assemblyscript-pdk | [NPM](https://www.npmjs.com/package/@extism/as-pdk) |
| .NET PDK | <img alt=".NET PDK" src="https://extism.org/img/sdk-languages/dotnet.svg" width="50px"/> | https://github.com/extism/dotnet-pdk <br/>(supports C# & F#!) | https://www.nuget.org/packages/Extism.Pdk |
| .NET PDK | <img alt=".NET PDK" src="https://extism.org/img/sdk-languages/dotnet.svg" width="50px"/> | https://github.com/extism/dotnet-pdk <br/>(supports C# & F#!) | [Nuget](https://www.nuget.org/packages/Extism.Pdk) |
| C PDK | <img alt="C PDK" src="https://extism.org/img/sdk-languages/c.svg" width="50px"/> | https://github.com/extism/c-pdk | N/A |
| C++ PDK | <img alt="C++ PDK" src="https://extism.org/img/sdk-languages/cpp.svg" width="50px"/> | https://github.com/extism/cpp-pdk | N/A |
| Zig PDK | <img alt="Zig PDK" src="https://extism.org/img/sdk-languages/zig.svg" width="50px"/> | https://github.com/extism/zig-pdk | N/A |
# Generating Bindings
It's often very useful to define a schema to describe the function signatures
and types you want to use between Extism SDK and PDK languages.
[XTP Bindgen](https://github.com/dylibso/xtp-bindgen) is an open source
framework to generate PDK bindings for Extism plug-ins. It's used by the
[XTP Platform](https://www.getxtp.com/), but can be used outside of the platform
to define any Extism compatible plug-in system.
## 1. Install the `xtp` CLI.
See installation instructions
[here](https://docs.xtp.dylibso.com/docs/cli#installation).
## 2. Create a schema using our OpenAPI-inspired IDL:
```yaml
version: v1-draft
exports:
CountVowels:
input:
type: string
contentType: text/plain; charset=utf-8
output:
$ref: "#/components/schemas/VowelReport"
contentType: application/json
# components.schemas defined in example-schema.yaml...
```
> See an example in [example-schema.yaml](./example-schema.yaml), or a full
> "kitchen sink" example on
> [the docs page](https://docs.xtp.dylibso.com/docs/concepts/xtp-schema/).
## 3. Generate bindings to use from your plugins:
```
xtp plugin init --schema-file ./example-schema.yaml
> 1. TypeScript
2. Go
3. Rust
4. Python
5. C#
6. Zig
7. C++
8. GitHub Template
9. Local Template
```
This will create an entire boilerplate plugin project for you to get started
with. Implement the empty function(s), and run `xtp plugin build` to compile
your plugin.
> For more information about XTP Bindgen, see the
> [dylibso/xtp-bindgen](https://github.com/dylibso/xtp-bindgen) repository and
> the official
> [XTP Schema documentation](https://docs.xtp.dylibso.com/docs/concepts/xtp-schema).
# Support
## Discord

View File

@@ -55,7 +55,7 @@ encoding!(pub Json, serde_json::to_vec, serde_json::from_slice);
#[cfg(feature = "msgpack")]
encoding!(pub Msgpack, rmp_serde::to_vec, rmp_serde::from_slice);
impl<'a> ToBytes<'a> for serde_json::Value {
impl ToBytes<'_> for serde_json::Value {
type Bytes = Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -85,7 +85,7 @@ impl<T: AsRef<[u8]>> From<T> for Base64<T> {
}
}
impl<'a, T: AsRef<[u8]>> ToBytes<'a> for Base64<T> {
impl<T: AsRef<[u8]>> ToBytes<'_> for Base64<T> {
type Bytes = String;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -124,7 +124,7 @@ impl<T: prost::Message> From<T> for Prost<T> {
}
#[cfg(feature = "prost")]
impl<'a, T: prost::Message> ToBytes<'a> for Prost<T> {
impl<T: prost::Message> ToBytes<'_> for Prost<T> {
type Bytes = Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -146,7 +146,7 @@ impl<T: Default + prost::Message> FromBytesOwned for Prost<T> {
pub struct Protobuf<T: protobuf::Message>(pub T);
#[cfg(feature = "protobuf")]
impl<'a, T: protobuf::Message> ToBytes<'a> for Protobuf<T> {
impl<T: protobuf::Message> ToBytes<'_> for Protobuf<T> {
type Bytes = Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {

View File

@@ -62,7 +62,7 @@ fn rountrip_option() {
}
#[cfg(all(feature = "raw", target_endian = "little"))]
mod tests {
mod raw_tests {
use crate::*;
#[test]

View File

@@ -61,21 +61,21 @@ pub trait ToBytes<'a> {
fn to_bytes(&self) -> Result<Self::Bytes, Error>;
}
impl<'a> ToBytes<'a> for () {
impl ToBytes<'_> for () {
type Bytes = [u8; 0];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
Ok([])
}
}
impl<'a> ToBytes<'a> for Vec<u8> {
impl ToBytes<'_> for Vec<u8> {
type Bytes = Vec<u8>;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
Ok(self.clone())
}
}
impl<'a> ToBytes<'a> for String {
impl ToBytes<'_> for String {
type Bytes = String;
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
Ok(self.clone())
@@ -96,7 +96,7 @@ impl<'a> ToBytes<'a> for &'a str {
}
}
impl<'a> ToBytes<'a> for f64 {
impl ToBytes<'_> for f64 {
type Bytes = [u8; 8];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -104,7 +104,7 @@ impl<'a> ToBytes<'a> for f64 {
}
}
impl<'a> ToBytes<'a> for f32 {
impl ToBytes<'_> for f32 {
type Bytes = [u8; 4];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -112,7 +112,7 @@ impl<'a> ToBytes<'a> for f32 {
}
}
impl<'a> ToBytes<'a> for i64 {
impl ToBytes<'_> for i64 {
type Bytes = [u8; 8];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -120,7 +120,7 @@ impl<'a> ToBytes<'a> for i64 {
}
}
impl<'a> ToBytes<'a> for i32 {
impl ToBytes<'_> for i32 {
type Bytes = [u8; 4];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -128,7 +128,7 @@ impl<'a> ToBytes<'a> for i32 {
}
}
impl<'a> ToBytes<'a> for u64 {
impl ToBytes<'_> for u64 {
type Bytes = [u8; 8];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
@@ -136,7 +136,7 @@ impl<'a> ToBytes<'a> for u64 {
}
}
impl<'a> ToBytes<'a> for u32 {
impl ToBytes<'_> for u32 {
type Bytes = [u8; 4];
fn to_bytes(&self) -> Result<Self::Bytes, Error> {

28
example-schema.yaml Normal file
View File

@@ -0,0 +1,28 @@
# yaml-language-server: $schema=https://xtp.dylibso.com/assets/wasm/schema.json
# Learn more at https://docs.xtp.dylibso.com/docs/concepts/xtp-schema
version: v1-draft
exports:
CountVowels:
input:
type: string
contentType: text/plain; charset=utf-8
output:
$ref: "#/components/schemas/VowelReport"
contentType: application/json
components:
schemas:
VowelReport:
description: The result of counting vowels on the Vowels input.
properties:
count:
type: integer
format: int32
description: The count of vowels for input string.
total:
type: integer
format: int32
description: The cumulative amount of vowels counted, if this keeps state across multiple function calls.
nullable: true
vowels:
type: string
description: The set of vowels used to get the count, e.g. "aAeEiIoOuU"

View File

@@ -269,8 +269,8 @@ pub struct Manifest {
/// Config values are made accessible using the PDK `extism_config_get` function
#[serde(default)]
pub config: BTreeMap<String, String>,
#[serde(default)]
#[serde(default)]
/// Specifies which hosts may be accessed via HTTP, if this is empty then
/// no hosts may be accessed. Wildcards may be used.
pub allowed_hosts: Option<Vec<String>>,
@@ -417,14 +417,14 @@ mod wasmdata {
}
}
impl<'a> From<Manifest> for std::borrow::Cow<'a, [u8]> {
impl From<Manifest> for std::borrow::Cow<'_, [u8]> {
fn from(m: Manifest) -> Self {
let s = serde_json::to_vec(&m).unwrap();
std::borrow::Cow::Owned(s)
}
}
impl<'a> From<&Manifest> for std::borrow::Cow<'a, [u8]> {
impl From<&Manifest> for std::borrow::Cow<'_, [u8]> {
fn from(m: &Manifest) -> Self {
let s = serde_json::to_vec(&m).unwrap();
std::borrow::Cow::Owned(s)

View File

@@ -34,7 +34,7 @@ register-filesystem = [] # enables wasm to be loaded from disk
http = ["ureq"] # enables extism_http_request
[build-dependencies]
cbindgen = { version = "0.27", default-features = false }
cbindgen = { version = "0.28", default-features = false }
[dev-dependencies]
criterion = "0.5.1"

View File

@@ -199,7 +199,7 @@ pub enum WasmInput<'a> {
ManifestRef(&'a Manifest),
}
impl<'a> From<Manifest> for WasmInput<'a> {
impl From<Manifest> for WasmInput<'_> {
fn from(value: Manifest) -> Self {
WasmInput::Manifest(value)
}
@@ -229,7 +229,7 @@ impl<'a> From<&'a str> for WasmInput<'a> {
}
}
impl<'a> From<Vec<u8>> for WasmInput<'a> {
impl From<Vec<u8>> for WasmInput<'_> {
fn from(value: Vec<u8>) -> Self {
WasmInput::Data(value.into())
}
@@ -325,6 +325,36 @@ fn relink(
get_log_level() -> I32;
);
for (name, module) in modules.iter() {
if name == EXTISM_ENV_MODULE {
continue;
}
for import in module.imports() {
if import.module() == EXTISM_ENV_MODULE
&& modules[EXTISM_ENV_MODULE]
.get_export(import.name())
.is_none()
&& linker
.get(&mut store, EXTISM_ENV_MODULE, import.name())
.is_none()
{
let (kind, ty) = match import.ty() {
ExternType::Func(t) => ("function", t.to_string()),
ExternType::Global(t) => ("global", t.content().to_string()),
ExternType::Table(t) => ("table", t.element().to_string()),
ExternType::Memory(_) => ("memory", String::new()),
};
anyhow::bail!(
"Invalid {kind} import from extism:host/env: {} {ty}\n\n\
Note: This may indicate that the PDK that was used to build this plugin has additional features that aren't \
available in this version of the SDK, try updating the SDK to the latest version.",
import.name(),
)
}
}
}
let mut linked = BTreeSet::new();
linker.module(&mut store, EXTISM_ENV_MODULE, &modules[EXTISM_ENV_MODULE])?;
linked.insert(EXTISM_ENV_MODULE.to_string());
@@ -530,7 +560,7 @@ impl Plugin {
}
/// Returns `true` if the given function exists, otherwise `false`
pub fn function_exists(&mut self, function: impl AsRef<str>) -> bool {
pub fn function_exists(&self, function: impl AsRef<str>) -> bool {
self.modules[MAIN_KEY]
.get_export(function.as_ref())
.map(|x| {
@@ -906,8 +936,7 @@ impl Plugin {
}
// on extism error
if output_res.is_ok() && self.output.error_offset != 0 && self.output.error_length != 0
{
if output_res.is_ok() && self.extism_error_is_set() {
let handle = MemoryHandle {
offset: self.output.error_offset,
length: self.output.error_length,
@@ -927,7 +956,7 @@ impl Plugin {
}
Err(msg) => {
res = Err(Error::msg(format!(
"Call to Extism plugin function {name} encountered an error: {}",
"unable to load error message from memory: {}",
msg,
)));
}
@@ -994,11 +1023,12 @@ impl Plugin {
plugin = self.id.to_string(),
"WASI exit code: {}", exit_code
);
if exit_code == 0 {
if exit_code == 0 && !self.extism_error_is_set() {
return Ok(0);
}
return Err((e.context("WASI exit code"), exit_code));
return Err((e, exit_code));
}
// Handle timeout interrupts
@@ -1026,6 +1056,10 @@ impl Plugin {
}
}
fn extism_error_is_set(&self) -> bool {
self.output.error_offset != 0 && self.output.error_length != 0
}
/// Call a function by name with the given input, the return value is
/// the output data returned by the plugin. The return type can be anything that implements
/// [FromBytes]. This data will be invalidated next time the plugin is called.
@@ -1121,6 +1155,25 @@ impl Plugin {
anyhow::bail!("Plugin::clear_error failed, extism:host/env::error_set not found")
}
}
/// Returns the amount of fuel consumed by the plugin.
///
/// This function calculates the difference between the initial fuel and the remaining fuel.
/// If either the initial fuel or the remaining fuel is not set, it returns `None`.
///
/// # Returns
///
/// * `Some(u64)` - The amount of fuel consumed.
/// * `None` - If the initial fuel or remaining fuel is not set.
pub fn fuel_consumed(&self) -> Option<u64> {
self.fuel.map(|x| {
x.saturating_sub(
self.store
.get_fuel()
.expect("fuel support should be enabled to use fuel"),
)
})
}
}
// Enumerates the PDK languages that need some additional initialization
@@ -1164,7 +1217,7 @@ macro_rules! typed_plugin {
impl TryFrom<$crate::Plugin> for $name {
type Error = $crate::Error;
fn try_from(mut x: $crate::Plugin) -> Result<Self, Self::Error> {
fn try_from(x: $crate::Plugin) -> Result<Self, Self::Error> {
$(
if !x.function_exists(stringify!($f)) {
return Err($crate::Error::msg(format!("Invalid function: {}", stringify!($f))));

View File

@@ -314,30 +314,53 @@ pub unsafe extern "C" fn extism_compiled_plugin_new(
) -> *mut CompiledPlugin {
trace!("Call to extism_plugin_new with wasm pointer {:?}", wasm);
let data = std::slice::from_raw_parts(wasm, wasm_size as usize);
let mut builder = PluginBuilder::new(data).with_wasi(with_wasi);
if !functions.is_null() {
for i in 0..n_functions {
unsafe {
let f = *functions.add(i as usize);
if f.is_null() {
continue;
let funcs = (0..n_functions)
.map(|i| unsafe { *functions.add(i as usize) })
.map(|ptr| {
if ptr.is_null() {
return Err("Cannot pass null pointer");
}
if let Some(f) = (*f).0.take() {
builder.options.functions.push(f);
} else {
let e = std::ffi::CString::new(
"Function cannot be registered with multiple different Plugins",
)
.unwrap();
let ExtismFunction(func) = &*ptr;
let Some(func) = func.take() else {
return Err("Function cannot be registered with multiple different Plugins");
};
Ok(func)
})
.collect::<Result<Vec<_>, _>>()
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(e.to_string()).unwrap();
*errmsg = e.into_raw();
return std::ptr::null_mut();
}
}
Vec::new()
});
if funcs.len() != n_functions as usize {
return std::ptr::null_mut();
}
builder = builder.with_functions(funcs);
}
Box::into_raw(Box::new(CompiledPlugin::new(builder).unwrap()))
CompiledPlugin::new(builder)
.map(|v| Box::into_raw(Box::new(v)))
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!(
"Unable to compile Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
std::ptr::null_mut()
})
}
/// Free `ExtismCompiledPlugin`
@@ -369,41 +392,52 @@ pub unsafe extern "C" fn extism_plugin_new(
errmsg: *mut *mut std::ffi::c_char,
) -> *mut Plugin {
let data = std::slice::from_raw_parts(wasm, wasm_size as usize);
let mut funcs = vec![];
if !functions.is_null() {
for i in 0..n_functions {
unsafe {
let f = *functions.add(i as usize);
if f.is_null() {
continue;
let funcs = if functions.is_null() {
vec![]
} else {
let funcs = (0..n_functions)
.map(|i| unsafe { *functions.add(i as usize) })
.map(|ptr| {
if ptr.is_null() {
return Err("Cannot pass null pointer");
}
if let Some(f) = (*f).0.take() {
funcs.push(f);
} else {
let e = std::ffi::CString::new(
"Function cannot be registered with multiple different Plugins",
)
.unwrap();
let ExtismFunction(func) = &*ptr;
let Some(func) = func.take() else {
return Err("Function cannot be registered with multiple different Plugins");
};
Ok(func)
})
.collect::<Result<Vec<_>, _>>()
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(e.to_string()).unwrap();
*errmsg = e.into_raw();
return std::ptr::null_mut();
}
}
}
}
Vec::new()
});
let plugin = Plugin::new(data, funcs, with_wasi);
match plugin {
Err(e) => {
if funcs.len() != n_functions as usize {
return std::ptr::null_mut();
}
funcs
};
Plugin::new(data, funcs, with_wasi)
.map(|v| Box::into_raw(Box::new(v)))
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!("Unable to create Extism plugin: {}", e))
.unwrap();
let e = std::ffi::CString::new(format!(
"Unable to compile Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
std::ptr::null_mut()
}
Ok(p) => Box::into_raw(Box::new(p)),
}
})
}
/// Create a new plugin from an `ExtismCompiledPlugin`
@@ -416,8 +450,11 @@ pub unsafe extern "C" fn extism_plugin_new_from_compiled(
match plugin {
Err(e) => {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!("Unable to create Extism plugin: {}", e))
.unwrap();
let e = std::ffi::CString::new(format!(
"Unable to create Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
std::ptr::null_mut()
@@ -442,30 +479,38 @@ pub unsafe extern "C" fn extism_plugin_new_with_fuel_limit(
wasm
);
let data = std::slice::from_raw_parts(wasm, wasm_size as usize);
let mut funcs = vec![];
let funcs = if functions.is_null() {
vec![]
} else {
let funcs = (0..n_functions)
.map(|i| unsafe { *functions.add(i as usize) })
.map(|ptr| {
if ptr.is_null() {
return Err("Cannot pass null pointer");
}
if !functions.is_null() {
for i in 0..n_functions {
unsafe {
let f = *functions.add(i as usize);
if f.is_null() {
continue;
let ExtismFunction(func) = &*ptr;
let Some(func) = func.take() else {
return Err("Function cannot be registered with multiple different Plugins");
};
Ok(func)
})
.collect::<Result<Vec<_>, _>>()
.unwrap_or_else(|e| {
if !errmsg.is_null() {
let e = std::ffi::CString::new(e.to_string()).unwrap();
*errmsg = e.into_raw();
}
if let Some(f) = (*f).0.take() {
funcs.push(f);
} else {
if !errmsg.is_null() {
let e = std::ffi::CString::new(
"Function cannot be registered with multiple different Plugins",
)
.unwrap();
*errmsg = e.into_raw();
}
return std::ptr::null_mut();
}
}
Vec::new()
});
if funcs.len() != n_functions as usize {
return std::ptr::null_mut();
}
}
funcs
};
let compiled = match CompiledPlugin::new(
PluginBuilder::new(data)
@@ -476,8 +521,11 @@ pub unsafe extern "C" fn extism_plugin_new_with_fuel_limit(
Ok(x) => x,
Err(e) => {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!("Unable to compile Extism plugin: {}", e))
.unwrap();
let e = std::ffi::CString::new(format!(
"Unable to compile Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
return std::ptr::null_mut();
@@ -489,8 +537,11 @@ pub unsafe extern "C" fn extism_plugin_new_with_fuel_limit(
match plugin {
Err(e) => {
if !errmsg.is_null() {
let e = std::ffi::CString::new(format!("Unable to create Extism plugin: {}", e))
.unwrap();
let e = std::ffi::CString::new(format!(
"Unable to create Extism plugin: {}",
e.root_cause(),
))
.unwrap();
*errmsg = e.into_raw();
}
std::ptr::null_mut()
@@ -848,7 +899,7 @@ fn set_log_file(log_file: impl Into<std::path::PathBuf>, filter: &str) -> Result
Ok(())
}
static mut LOG_BUFFER: Option<LogBuffer> = None;
static LOG_BUFFER: std::sync::Mutex<Option<LogBuffer>> = std::sync::Mutex::new(None);
/// Enable a custom log handler, this will buffer logs until `extism_log_drain` is called
/// Log level should be one of: info, error, trace, debug, warn
@@ -880,8 +931,8 @@ unsafe fn set_log_buffer(filter: &str) -> Result<(), Error> {
x.parse_lossy(filter)
}
});
LOG_BUFFER = Some(LogBuffer::default());
let buf = LOG_BUFFER.clone().unwrap();
*LOG_BUFFER.lock().unwrap() = Some(LogBuffer::default());
let buf = LOG_BUFFER.lock().unwrap().clone().unwrap();
cfg.with_ansi(false)
.with_writer(move || buf.clone())
.try_init()
@@ -893,7 +944,7 @@ unsafe fn set_log_buffer(filter: &str) -> Result<(), Error> {
/// Calls the provided callback function for each buffered log line.
/// This is only needed when `extism_log_custom` is used.
pub unsafe extern "C" fn extism_log_drain(handler: ExtismLogDrainFunctionType) {
if let Some(buf) = LOG_BUFFER.as_mut() {
if let Some(buf) = LOG_BUFFER.lock().unwrap().as_mut() {
if let Ok(mut buf) = buf.buffer.lock() {
for (line, len) in buf.drain(..) {
handler(line.as_ptr(), len as u64);

View File

@@ -258,6 +258,23 @@ fn test_fuel() {
}
}
#[test]
fn test_fuel_consumption() {
let manifest = Manifest::new([extism_manifest::Wasm::data(WASM_LOOP)]);
let mut plugin = PluginBuilder::new(manifest)
.with_wasi(true)
.with_fuel_limit(10000)
.build()
.unwrap();
let output: Result<&[u8], Error> = plugin.call("loop_forever", "abc123");
assert!(output.is_err());
let fuel_consumed = plugin.fuel_consumed().unwrap();
println!("Fuel consumed: {}", fuel_consumed);
assert!(fuel_consumed > 0);
}
#[test]
#[cfg(feature = "http")]
fn test_http_timeout() {
@@ -447,7 +464,7 @@ fn hello_world_set_error(
_user_data: UserData<()>,
) -> Result<(), Error> {
plugin.set_error("TEST")?;
outputs[0] = inputs[0].clone();
outputs[0] = inputs[0];
Ok(())
}
@@ -544,7 +561,7 @@ fn hello_world_user_data(
let mut data = data.lock().unwrap();
let s = _plugin.memory_get_val(&inputs[0])?;
data.write_all(s)?;
outputs[0] = inputs[0].clone();
outputs[0] = inputs[0];
Ok(())
}

View File

@@ -22,18 +22,18 @@ pub(crate) struct Timer {
#[cfg(not(target_family = "windows"))]
extern "C" fn cleanup_timer() {
let mut timer = match unsafe { TIMER.lock() } {
let mut timer = match TIMER.lock() {
Ok(x) => x,
Err(e) => e.into_inner(),
};
drop(timer.take());
}
static mut TIMER: std::sync::Mutex<Option<Timer>> = std::sync::Mutex::new(None);
static TIMER: std::sync::Mutex<Option<Timer>> = std::sync::Mutex::new(None);
impl Timer {
pub(crate) fn tx() -> std::sync::mpsc::Sender<TimerAction> {
let mut timer = match unsafe { TIMER.lock() } {
let mut timer = match TIMER.lock() {
Ok(x) => x,
Err(e) => e.into_inner(),
};
@@ -92,25 +92,39 @@ impl Timer {
loop {
if plugins.is_empty() {
if let Ok(x) = rx.recv() {
handle!(x)
handle!(x);
}
}
plugins = plugins
.into_iter()
.filter(|(_k, (engine, end))| {
if let Some(end) = end {
let now = std::time::Instant::now();
if end <= &now {
engine.increment_epoch();
return false;
let mut timeout: Option<std::time::Duration> = None;
plugins.retain(|_k, (engine, end)| {
if let Some(end) = end {
let now = std::time::Instant::now();
if *end <= now {
engine.increment_epoch();
return false;
} else {
let time_left =
(*end - now).saturating_sub(std::time::Duration::from_millis(1));
if let Some(t) = &timeout {
if time_left < *t {
timeout = Some(time_left);
}
} else {
timeout = Some(time_left);
}
}
true
})
.collect();
}
for x in rx.try_iter() {
true
});
if let Some(timeout) = timeout {
if let Ok(x) = rx.recv_timeout(timeout) {
handle!(x)
}
} else if let Ok(x) = rx.recv() {
handle!(x)
}
}