mirror of
https://github.com/extism/extism.git
synced 2026-04-23 03:00:11 -04:00
Compare commits
2 Commits
v1.0.0-rc1
...
add-elixir
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c31215ce7 | ||
|
|
fc95a99e40 |
30
.github/actions/extism/action.yml
vendored
30
.github/actions/extism/action.yml
vendored
@@ -1,30 +0,0 @@
|
||||
on: [workflow_call]
|
||||
|
||||
name: libextism
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
- name: Cache Rust environment
|
||||
uses: Swatinem/rust-cache@v1
|
||||
- name: Cache libextism
|
||||
id: cache-libextism
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target/**
|
||||
key: ${{ runner.os }}-libextism-${{ hashFiles('runtime/**') }}-${{ hashFiles('manifest/**') }}-${{ hashFiles('libextism/**') }}
|
||||
- name: Build
|
||||
if: steps.cache-libextism.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: cargo build --release -p libextism
|
||||
- name: Install extism shared library
|
||||
shell: bash
|
||||
run: |
|
||||
sudo make install
|
||||
41
.github/dependabot.yml
vendored
41
.github/dependabot.yml
vendored
@@ -1,41 +0,0 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "cargo" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "pip"
|
||||
directory: "python"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "mix"
|
||||
directory: "elixir"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "node"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "composer"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "bundler"
|
||||
directory: "ruby"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
28
.github/workflows/browser-ci.yml
vendored
28
.github/workflows/browser-ci.yml
vendored
@@ -1,28 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Browser CI
|
||||
|
||||
jobs:
|
||||
node:
|
||||
name: Browser
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup Node env
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Test Browser Runtime
|
||||
run: |
|
||||
cd browser
|
||||
npm i
|
||||
npm run test
|
||||
31
.github/workflows/ci-cpp.yml
vendored
31
.github/workflows/ci-cpp.yml
vendored
@@ -1,31 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: C++ CI
|
||||
|
||||
jobs:
|
||||
cpp:
|
||||
name: C++
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Install C++ SDK deps
|
||||
if: ${{ matrix.os == 'macos-latest' }}
|
||||
run: |
|
||||
brew install jsoncpp googletest pkg-config
|
||||
- name: Install C++ SDK deps
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
sudo apt-get install g++ libjsoncpp-dev libgtest-dev pkg-config
|
||||
- name: Run C++ tests
|
||||
run: |
|
||||
cd cpp
|
||||
LD_LIBRARY_PATH=/usr/local/lib make example
|
||||
LD_LIBRARY_PATH=/usr/local/lib make test
|
||||
28
.github/workflows/ci-d.yml
vendored
28
.github/workflows/ci-d.yml
vendored
@@ -1,28 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: D CI
|
||||
|
||||
jobs:
|
||||
d:
|
||||
name: D
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
# TODO: Use multiple versions once stable
|
||||
d_version: [ldc-1.33.0]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup D environment
|
||||
uses: dlang-community/setup-dlang@v1
|
||||
with:
|
||||
compiler: ${{ matrix.d_version }}
|
||||
|
||||
- name: Test D Host SDK
|
||||
run: |
|
||||
dub --version
|
||||
LD_LIBRARY_PATH=/usr/local/lib dub test
|
||||
26
.github/workflows/ci-dotnet.yml
vendored
26
.github/workflows/ci-dotnet.yml
vendored
@@ -1,26 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: .NET CI
|
||||
|
||||
jobs:
|
||||
dotnet:
|
||||
name: .NET
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v3.0.3
|
||||
with:
|
||||
dotnet-version: 7.x
|
||||
- name: Test .NET Sdk
|
||||
run: |
|
||||
cd dotnet
|
||||
LD_LIBRARY_PATH=/usr/local/lib dotnet test ./Extism.sln
|
||||
33
.github/workflows/ci-elixir.yml
vendored
33
.github/workflows/ci-elixir.yml
vendored
@@ -1,33 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Elixir CI
|
||||
|
||||
jobs:
|
||||
elixir:
|
||||
name: Elixir
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
MIX_ENV: test
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup Elixir Host SDK
|
||||
if: ${{ runner.os != 'macOS' }}
|
||||
uses: erlef/setup-beam@v1
|
||||
with:
|
||||
experimental-otp: true
|
||||
otp-version: '25.0.4'
|
||||
elixir-version: '1.14.0'
|
||||
|
||||
- name: Test Elixir Host SDK
|
||||
if: ${{ runner.os != 'macOS' }}
|
||||
run: |
|
||||
cd elixir
|
||||
LD_LIBRARY_PATH=/usr/local/lib mix do deps.get, test
|
||||
27
.github/workflows/ci-go.yml
vendored
27
.github/workflows/ci-go.yml
vendored
@@ -1,27 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Go CI
|
||||
|
||||
jobs:
|
||||
go:
|
||||
name: Go
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup Go env
|
||||
uses: actions/setup-go@v3
|
||||
|
||||
- name: Test Go Host SDK
|
||||
run: |
|
||||
go version
|
||||
LD_LIBRARY_PATH=/usr/local/lib go test
|
||||
cd go
|
||||
LD_LIBRARY_PATH=/usr/local/lib go run main.go | grep "Hello from Go!"
|
||||
39
.github/workflows/ci-haskell.yml
vendored
39
.github/workflows/ci-haskell.yml
vendored
@@ -1,39 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Haskell CI
|
||||
|
||||
jobs:
|
||||
haskell:
|
||||
name: Haskell
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup Haskell env
|
||||
uses: haskell/actions/setup@v2
|
||||
with:
|
||||
enable-stack: false
|
||||
- name: Cache Haskell
|
||||
id: cache-haskell
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ./haskell/dist-newstyle
|
||||
key: ${{ runner.os }}-haskell-${{ hashFiles('haskell/**') }}
|
||||
- name: Build Haskell Host SDK
|
||||
if: steps.cache-haskell.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd haskell
|
||||
cabal update
|
||||
LD_LIBRARY_PATH=/usr/local/lib cabal build
|
||||
- name: Test Haskell SDK
|
||||
run: |
|
||||
cd haskell
|
||||
cabal update
|
||||
LD_LIBRARY_PATH=/usr/local/lib cabal test
|
||||
29
.github/workflows/ci-java.yml
vendored
29
.github/workflows/ci-java.yml
vendored
@@ -1,29 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Java CI
|
||||
|
||||
jobs:
|
||||
java:
|
||||
name: Java
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
version: [11, 17]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '${{ matrix.version }}'
|
||||
- name: Test Java
|
||||
run: |
|
||||
cd java
|
||||
mvn --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn verify
|
||||
|
||||
30
.github/workflows/ci-node.yml
vendored
30
.github/workflows/ci-node.yml
vendored
@@ -1,30 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Node CI
|
||||
|
||||
jobs:
|
||||
node:
|
||||
name: Node
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup Node env
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Test Node Host SDK
|
||||
run: |
|
||||
cd node
|
||||
npm i
|
||||
LD_LIBRARY_PATH=/usr/local/lib npm run build
|
||||
LD_LIBRARY_PATH=/usr/local/lib npm run example
|
||||
LD_LIBRARY_PATH=/usr/local/lib npm run test
|
||||
40
.github/workflows/ci-ocaml.yml
vendored
40
.github/workflows/ci-ocaml.yml
vendored
@@ -1,40 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: OCaml CI
|
||||
|
||||
jobs:
|
||||
ocaml:
|
||||
name: OCaml
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup OCaml env
|
||||
uses: ocaml/setup-ocaml@v2
|
||||
with:
|
||||
ocaml-compiler: ocaml-base-compiler.5.0.0
|
||||
- name: Cache OCaml
|
||||
id: cache-ocaml
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: _build
|
||||
key: ${{ runner.os }}-ocaml-${{ hashFiles('ocaml/**.ml') }}-${{ hashFiles('dune-project') }}
|
||||
- name: Build OCaml Host SDK
|
||||
if: steps.cache-ocaml.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
opam install -y --deps-only .
|
||||
cd ocaml
|
||||
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune build
|
||||
- name: Test OCaml Host SDK
|
||||
run: |
|
||||
opam install -y --deps-only .
|
||||
cd ocaml
|
||||
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune exec ./bin/main.exe ../wasm/code.wasm count_vowels -- --input "qwertyuiop"
|
||||
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune runtest
|
||||
32
.github/workflows/ci-php.yml
vendored
32
.github/workflows/ci-php.yml
vendored
@@ -1,32 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: PHP CI
|
||||
|
||||
jobs:
|
||||
php:
|
||||
name: PHP
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup PHP env
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.1"
|
||||
extensions: ffi
|
||||
tools: composer
|
||||
env:
|
||||
fail-fast: true
|
||||
|
||||
- name: Test PHP SDK
|
||||
run: |
|
||||
cd php/example
|
||||
composer install
|
||||
php index.php
|
||||
32
.github/workflows/ci-python.yml
vendored
32
.github/workflows/ci-python.yml
vendored
@@ -1,32 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Python CI
|
||||
|
||||
jobs:
|
||||
python:
|
||||
name: Python
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup Python env
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.9"
|
||||
check-latest: true
|
||||
- name: Install Poetry
|
||||
uses: snok/install-poetry@v1
|
||||
- name: Test Python Host SDK
|
||||
run: |
|
||||
cd python
|
||||
cp ../README.md .
|
||||
poetry install --no-dev
|
||||
poetry run python example.py
|
||||
poetry run python -m unittest discover
|
||||
30
.github/workflows/ci-ruby.yml
vendored
30
.github/workflows/ci-ruby.yml
vendored
@@ -1,30 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Ruby CI
|
||||
|
||||
jobs:
|
||||
ruby:
|
||||
name: Ruby
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup Ruby env
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: "3.0"
|
||||
|
||||
- name: Test Ruby Host SDK
|
||||
run: |
|
||||
cd ruby
|
||||
bundle install
|
||||
ruby example.rb
|
||||
rake test
|
||||
|
||||
119
.github/workflows/ci-rust.yml
vendored
119
.github/workflows/ci-rust.yml
vendored
@@ -1,119 +0,0 @@
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- .github/actions/extism/**
|
||||
- .github/workflows/ci-rust.yml
|
||||
- convert/**
|
||||
- manifest/**
|
||||
- runtime/**
|
||||
- rust/**
|
||||
- libextism/**
|
||||
workflow_dispatch:
|
||||
|
||||
name: Rust CI
|
||||
|
||||
env:
|
||||
RUNTIME_CRATE: extism
|
||||
LIBEXTISM_CRATE: libextism
|
||||
|
||||
jobs:
|
||||
lib:
|
||||
name: Extism runtime lib
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
- name: Cache Rust environment
|
||||
uses: Swatinem/rust-cache@v1
|
||||
- name: Cache libextism
|
||||
id: cache-libextism
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target/release/libextism.*
|
||||
key: ${{ runner.os }}-libextism-${{ hashFiles('runtime/**') }}-${{ hashFiles('manifest/**') }}-${{ hashFiles('convert/**') }}
|
||||
- name: Cache target
|
||||
id: cache-target
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target/**
|
||||
key: ${{ runner.os }}-target-${{ github.sha }}
|
||||
- name: Build
|
||||
if: steps.cache-libextism.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: cargo build --release -p ${{ env.LIBEXTISM_CRATE }}
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: libextism-${{ matrix.os }}
|
||||
path: |
|
||||
target/release/libextism.*
|
||||
lint_and_test:
|
||||
name: Extism runtime lint and test
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
- name: Cache Rust environment
|
||||
uses: Swatinem/rust-cache@v1
|
||||
- name: Cache target
|
||||
id: cache-target
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target/**
|
||||
key: ${{ runner.os }}-target-${{ github.sha }}
|
||||
- name: Format
|
||||
run: cargo fmt --check -p ${{ env.RUNTIME_CRATE }}
|
||||
- name: Lint
|
||||
run: cargo clippy --release --all-features --no-deps -p ${{ env.RUNTIME_CRATE }}
|
||||
- name: Test
|
||||
run: cargo test --release -p ${{ env.RUNTIME_CRATE }}
|
||||
- name: Test all features
|
||||
run: cargo test --all-features --release -p ${{ env.RUNTIME_CRATE }}
|
||||
- name: Test no features
|
||||
run: cargo test --no-default-features --release -p ${{ env.RUNTIME_CRATE }}
|
||||
bench:
|
||||
name: Benchmarking
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
- name: Cache Rust environment
|
||||
uses: Swatinem/rust-cache@v1
|
||||
- name: Cache target
|
||||
id: cache-target
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target/**
|
||||
key: ${{ runner.os }}-target-${{ github.sha }}
|
||||
- run: cargo install cargo-criterion
|
||||
- run: cargo criterion
|
||||
29
.github/workflows/ci-zig.yml
vendored
29
.github/workflows/ci-zig.yml
vendored
@@ -1,29 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Zig CI
|
||||
|
||||
jobs:
|
||||
zig:
|
||||
name: Zig
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
zig_version: ["master"] # eventually use multiple versions once stable
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/extism
|
||||
- name: Setup Zig env
|
||||
uses: goto-bus-stop/setup-zig@v2
|
||||
with:
|
||||
version: ${{ matrix.zig_version }}
|
||||
|
||||
- name: Test Zig Host SDK
|
||||
run: |
|
||||
zig version
|
||||
cd zig
|
||||
LD_LIBRARY_PATH=/usr/local/lib zig build test
|
||||
150
.github/workflows/ci.yml
vendored
150
.github/workflows/ci.yml
vendored
@@ -1,25 +1,171 @@
|
||||
on: [pull_request, workflow_dispatch]
|
||||
on: [push, pull_request]
|
||||
|
||||
name: CI
|
||||
|
||||
env:
|
||||
RUNTIME_MANIFEST: runtime/Cargo.toml
|
||||
RUNTIME_CRATE: extism-runtime
|
||||
RUST_SDK_CRATE: extism
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
name: Build & Test
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
MIX_ENV: test
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
rust:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
|
||||
- name: Cache Rust environment
|
||||
uses: Swatinem/rust-cache@v1
|
||||
|
||||
- name: Format
|
||||
run: cargo fmt --check -p ${{ env.RUNTIME_CRATE }}
|
||||
|
||||
- name: Build
|
||||
run: cargo build --release -p ${{ env.RUNTIME_CRATE }}
|
||||
|
||||
- name: Lint
|
||||
run: cargo clippy --release --no-deps -p ${{ env.RUNTIME_CRATE }}
|
||||
|
||||
- name: Test
|
||||
run: cargo test --all-features --release -p ${{ env.RUNTIME_CRATE }}
|
||||
|
||||
- name: Install extism shared library
|
||||
shell: bash
|
||||
run: sudo make install
|
||||
|
||||
- name: Setup Elixir Host SDK
|
||||
if: ${{ runner.os != 'macOS' }}
|
||||
uses: erlef/setup-beam@v1
|
||||
with:
|
||||
experimental-otp: true
|
||||
otp-version: '25.0.4'
|
||||
elixir-version: '1.14.0'
|
||||
|
||||
- name: Test Elixir Host SDK
|
||||
if: ${{ runner.os != 'macOS' }}
|
||||
run: |
|
||||
cd elixir
|
||||
LD_LIBRARY_PATH=/usr/local/lib mix do deps.get, test
|
||||
|
||||
- name: Setup Go env
|
||||
uses: actions/setup-go@v3
|
||||
|
||||
- name: Test Go Host SDK
|
||||
run: |
|
||||
go version
|
||||
cd go && LD_LIBRARY_PATH=/usr/local/lib go run main.go
|
||||
|
||||
- name: Setup Python env
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.9"
|
||||
check-latest: true
|
||||
|
||||
- name: Install Poetry
|
||||
uses: snok/install-poetry@v1
|
||||
|
||||
- name: Test Python Host SDK
|
||||
run: |
|
||||
cd python
|
||||
poetry install
|
||||
poetry run python example.py
|
||||
poetry run python -m unittest discover
|
||||
|
||||
- name: Setup Ruby env
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: "3.0"
|
||||
|
||||
- name: Test Ruby Host SDK
|
||||
run: |
|
||||
cd ruby
|
||||
bundle install
|
||||
ruby example.rb
|
||||
rake test
|
||||
|
||||
- name: Setup Node env
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Test Node Host SDK
|
||||
run: |
|
||||
cd node
|
||||
npm i
|
||||
npm run build
|
||||
LD_LIBRARY_PATH=/usr/local/lib node example.js
|
||||
|
||||
- name: Test Rust Host SDK
|
||||
run: LD_LIBRARY_PATH=/usr/local/lib cargo test --release -p ${{ env.RUST_SDK_CRATE }}
|
||||
|
||||
# - name: Setup OCaml env
|
||||
# uses: ocaml/setup-ocaml@v2
|
||||
|
||||
# - name: Test OCaml Host SDK
|
||||
# run: |
|
||||
# opam install -y .
|
||||
# cd ocaml
|
||||
# opam exec -- dune exec extism
|
||||
|
||||
- name: Setup Haskell env
|
||||
uses: haskell/actions/setup@v2
|
||||
with:
|
||||
enable-stack: true
|
||||
stack-version: "latest"
|
||||
|
||||
- name: Test Haskell SDK
|
||||
run: |
|
||||
cd haskell
|
||||
LD_LIBRARY_PATH=/usr/local/lib stack test
|
||||
|
||||
- name: Setup PHP env
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.1"
|
||||
extensions: ffi
|
||||
tools: composer
|
||||
env:
|
||||
fail-fast: true
|
||||
|
||||
- name: Test PHP SDK
|
||||
run: |
|
||||
cd php/example
|
||||
composer install
|
||||
php index.php
|
||||
|
||||
sdk_api_coverage:
|
||||
name: SDK API Coverage Report
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Python env
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.9"
|
||||
check-latest: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install ripgrep
|
||||
pip3 install pycparser
|
||||
|
||||
- name: Run coverage script
|
||||
id: coverage
|
||||
run: |
|
||||
python scripts/sdk_coverage.py
|
||||
|
||||
|
||||
47
.github/workflows/kernel.yml
vendored
47
.github/workflows/kernel.yml
vendored
@@ -1,47 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- kernel/**
|
||||
|
||||
name: Kernel
|
||||
|
||||
jobs:
|
||||
kernel:
|
||||
name: Build extism-runtime.wasm
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
target: wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Install deps
|
||||
run: |
|
||||
sudo apt install wabt --yes
|
||||
|
||||
- name: Build kernel
|
||||
shell: bash
|
||||
continue-on-error: true
|
||||
run: |
|
||||
cd kernel
|
||||
sh build.sh
|
||||
git diff --exit-code
|
||||
export GIT_EXIT_CODE=$?
|
||||
|
||||
- uses: peter-evans/create-pull-request@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: ${{ env.GIT_EXIT_CODE }} != 0
|
||||
with:
|
||||
title: "update(kernel): extism-runtime.wasm in ${{ github.event.pull_request.head.ref }}"
|
||||
body: "Automated PR to update `runtime/src/extism-runtime.wasm` in PR #${{ github.event.number }}"
|
||||
base: "${{ github.event.pull_request.head.ref }}"
|
||||
branch: "update-kernel--${{ github.event.pull_request.head.ref }}"
|
||||
commit-message: "update(kernel): extism-runtime.wasm in ${{ github.event.pull_request.head.ref }}"
|
||||
delete-branch: true
|
||||
26
.github/workflows/release-convert.yaml
vendored
26
.github/workflows/release-convert.yaml
vendored
@@ -1,26 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Release extism-convert
|
||||
|
||||
jobs:
|
||||
release-convert:
|
||||
name: release-extism-convert
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Rust env
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Release Rust Convert Crate
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
|
||||
run: |
|
||||
cargo publish --manifest-path convert/Cargo.toml
|
||||
51
.github/workflows/release-dotnet-native.yaml
vendored
51
.github/workflows/release-dotnet-native.yaml
vendored
@@ -1,51 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Release .NET Native NuGet Packages
|
||||
|
||||
jobs:
|
||||
release-runtimes:
|
||||
name: release-dotnet-native
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
filter: tree:0
|
||||
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v3.0.3
|
||||
with:
|
||||
dotnet-version: 7.x
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
workflow: release.yml
|
||||
name: release-artifacts
|
||||
- name: Extract Archive
|
||||
run: |
|
||||
mkdir -p dotnet/nuget/runtimes/win-x64/native/
|
||||
tar -xvzf libextism-x86_64-pc-windows-msvc-main.tar.gz -C dotnet/nuget/runtimes/win-x64/native/
|
||||
|
||||
mkdir -p dotnet/nuget/runtimes/osx-arm64/native/
|
||||
tar -xvzf libextism-aarch64-apple-darwin-main.tar.gz -C dotnet/nuget/runtimes/osx-arm64/native/
|
||||
|
||||
mkdir -p dotnet/nuget/runtimes/osx-x64/native/
|
||||
tar -xvzf libextism-x86_64-apple-darwin-main.tar.gz -C dotnet/nuget/runtimes/osx-x64/native/
|
||||
|
||||
mkdir -p dotnet/nuget/runtimes/linux-x64/native/
|
||||
tar -xvzf libextism-x86_64-unknown-linux-gnu-main.tar.gz -C dotnet/nuget/runtimes/linux-x64/native/
|
||||
|
||||
mkdir -p dotnet/nuget/runtimes/linux-arm64/native/
|
||||
tar -xvzf libextism-aarch64-unknown-linux-gnu-main.tar.gz -C dotnet/nuget/runtimes/linux-arm64/native/
|
||||
|
||||
mkdir -p dotnet/nuget/runtimes/linux-musl-arm64/native/
|
||||
tar -xvzf libextism-aarch64-unknown-linux-musl-main.tar.gz -C dotnet/nuget/runtimes/linux-musl-arm64/native/
|
||||
|
||||
- name: Pack NuGet packages
|
||||
run: |
|
||||
find ./dotnet/nuget -type f -name "*.csproj" -exec dotnet pack {} -o release-artifacts \;
|
||||
|
||||
- name: Publish NuGet packages
|
||||
run: |
|
||||
dotnet nuget push --source https://api.nuget.org/v3/index.json ./release-artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }}
|
||||
32
.github/workflows/release-dotnet.yaml
vendored
32
.github/workflows/release-dotnet.yaml
vendored
@@ -1,32 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Release .NET SDK
|
||||
|
||||
jobs:
|
||||
release-sdks:
|
||||
name: release-dotnet
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Install extism shared library
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p /home/runner/.local/bin/
|
||||
export PATH="/home/runner/.local/bin/:$PATH"
|
||||
curl https://raw.githubusercontent.com/extism/cli/main/install.sh | sh
|
||||
extism --sudo --prefix /usr/local install
|
||||
- name: Setup .NET Core SDK
|
||||
uses: actions/setup-dotnet@v3.0.3
|
||||
with:
|
||||
dotnet-version: 7.x
|
||||
- name: Test .NET Sdk
|
||||
run: |
|
||||
cd dotnet
|
||||
LD_LIBRARY_PATH=/usr/local/lib dotnet test ./Extism.sln
|
||||
- name: Publish .NET Sdk
|
||||
run: |
|
||||
cd dotnet/src/Extism.Sdk/
|
||||
dotnet pack -c Release
|
||||
dotnet nuget push --source https://api.nuget.org/v3/index.json ./bin/Release/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }}
|
||||
34
.github/workflows/release-elixir.yaml
vendored
34
.github/workflows/release-elixir.yaml
vendored
@@ -1,34 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Release Elixir SDK
|
||||
|
||||
jobs:
|
||||
release-sdks:
|
||||
name: release-elixir
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Install extism shared library
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p /home/runner/.local/bin/
|
||||
export PATH="/home/runner/.local/bin/:$PATH"
|
||||
curl https://raw.githubusercontent.com/extism/cli/main/install.sh | sh
|
||||
extism --sudo --prefix /usr/local install
|
||||
- name: Setup Elixir Host SDK
|
||||
uses: erlef/setup-beam@v1
|
||||
with:
|
||||
experimental-otp: true
|
||||
otp-version: '25.0.4'
|
||||
elixir-version: '1.14.0'
|
||||
|
||||
- name: Publish Elixir Host SDK to hex.pm
|
||||
env:
|
||||
HEX_API_KEY: ${{ secrets.HEX_PM_API_TOKEN }}
|
||||
run: |
|
||||
cd elixir
|
||||
cp ../LICENSE .
|
||||
make publish
|
||||
|
||||
16
.github/workflows/release-haskell.yaml
vendored
16
.github/workflows/release-haskell.yaml
vendored
@@ -1,16 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Release Haskell SDK
|
||||
|
||||
jobs:
|
||||
release-sdks:
|
||||
name: release-rust
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: cachix/haskell-release-action@v1
|
||||
with:
|
||||
- hackage-token: "${{ secrets.HACKAGE_TOKEN }}"
|
||||
- work-dir: ./haskell
|
||||
22
.github/workflows/release-java.yml
vendored
22
.github/workflows/release-java.yml
vendored
@@ -1,22 +0,0 @@
|
||||
name: Publish package to the Maven Central Repository
|
||||
on:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
- name: Publish package
|
||||
env:
|
||||
JRELEASER_NEXUS2_USERNAME: ${{ secrets.JRELEASER_NEXUS2_USERNAME }}
|
||||
JRELEASER_NEXUS2_PASSWORD: ${{ secrets.JRELEASER_NEXUS2_PASSWORD }}
|
||||
JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }}
|
||||
JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }}
|
||||
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.JRELEASER_GPG_PUBLIC_KEY }}
|
||||
JRELEASER_GITHUB_TOKEN: "dummy"
|
||||
run: mvn -Prelease clean jreleaser:prepare deploy jreleaser:deploy -DaltDeploymentRepository=local::default::file:./target/staging-deploy
|
||||
26
.github/workflows/release-manifest.yaml
vendored
26
.github/workflows/release-manifest.yaml
vendored
@@ -1,26 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Release extism-manifest
|
||||
|
||||
jobs:
|
||||
release-manifest:
|
||||
name: release-extism-manifest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Rust env
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Release Rust Manifest Crate
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
|
||||
run: |
|
||||
cargo publish --manifest-path manifest/Cargo.toml
|
||||
30
.github/workflows/release-node.yaml
vendored
30
.github/workflows/release-node.yaml
vendored
@@ -1,30 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Release Node SDK
|
||||
|
||||
jobs:
|
||||
release-sdks:
|
||||
name: release-node
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node env
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_API_TOKEN }}
|
||||
CI: true
|
||||
|
||||
- name: Release Node Host SDK
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_API_TOKEN }}
|
||||
CI: true
|
||||
run: |
|
||||
cd node
|
||||
make publish
|
||||
|
||||
41
.github/workflows/release-python.yaml
vendored
41
.github/workflows/release-python.yaml
vendored
@@ -1,41 +0,0 @@
|
||||
name: Release Python SDK
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published, edited]
|
||||
|
||||
jobs:
|
||||
release-sdks:
|
||||
name: release-python
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install poetry
|
||||
run: pipx install poetry
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: install twine
|
||||
run: |
|
||||
pip install twine
|
||||
|
||||
- name: download release
|
||||
run: |
|
||||
tag='${{ github.ref }}'
|
||||
tag="${tag/refs\/tags\//}"
|
||||
mkdir dist
|
||||
cd dist
|
||||
gh release download "$tag" -p 'extism_sys-*'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: upload release
|
||||
run: |
|
||||
twine upload dist/*
|
||||
env:
|
||||
TWINE_USERNAME: ${{ secrets.PYPI_API_USER }}
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
||||
25
.github/workflows/release-ruby.yaml
vendored
25
.github/workflows/release-ruby.yaml
vendored
@@ -1,25 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Release Ruby SDK
|
||||
|
||||
jobs:
|
||||
release-sdks:
|
||||
name: release-ruby
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Ruby
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '3.1' # Version range or exact version of a Ruby version to use, using semvers version range syntax.
|
||||
|
||||
- name: Publish Ruby Gem
|
||||
env:
|
||||
RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_TOKEN }}
|
||||
run: |
|
||||
cd ruby
|
||||
make publish RUBYGEMS_API_KEY=$RUBYGEMS_API_KEY
|
||||
|
||||
26
.github/workflows/release-rust.yaml
vendored
26
.github/workflows/release-rust.yaml
vendored
@@ -1,26 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
name: Release Runtime/Rust SDK
|
||||
|
||||
jobs:
|
||||
release-runtime:
|
||||
name: release-rust
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Rust env
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Release Runtime
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
|
||||
run: |
|
||||
cargo publish --manifest-path runtime/Cargo.toml
|
||||
425
.github/workflows/release.yml
vendored
425
.github/workflows/release.yml
vendored
@@ -1,78 +1,29 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [ main ]
|
||||
tags:
|
||||
- 'v*'
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
name: Release
|
||||
|
||||
env:
|
||||
RUNTIME_MANIFEST: runtime/Cargo.toml
|
||||
RUNTIME_CRATE: libextism
|
||||
RUNTIME_CRATE: extism-runtime
|
||||
RUSTFLAGS: -C target-feature=-crt-static
|
||||
ARTIFACT_DIR: release-artifacts
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: ${{ matrix.os }} ${{ matrix.target }}
|
||||
runs-on: ${{ matrix.os }}-latest
|
||||
release-linux:
|
||||
name: linux
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: 'macos'
|
||||
target: 'x86_64-apple-darwin'
|
||||
artifact: 'libextism.dylib'
|
||||
static-artifact: 'libextism.a'
|
||||
pc-in: 'extism.pc.in'
|
||||
static-pc-in: 'extism-static.pc.in'
|
||||
- os: 'macos'
|
||||
target: 'aarch64-apple-darwin'
|
||||
artifact: 'libextism.dylib'
|
||||
static-artifact: 'libextism.a'
|
||||
pc-in: 'extism.pc.in'
|
||||
static-pc-in: 'extism-static.pc.in'
|
||||
- os: 'ubuntu'
|
||||
target: 'aarch64-unknown-linux-gnu'
|
||||
artifact: 'libextism.so'
|
||||
static-artifact: 'libextism.a'
|
||||
pc-in: 'extism.pc.in'
|
||||
static-pc-in: 'extism-static.pc.in'
|
||||
- os: 'ubuntu'
|
||||
target: 'aarch64-unknown-linux-musl'
|
||||
artifact: 'libextism.so'
|
||||
static-artifact: 'libextism.a'
|
||||
pc-in: 'extism.pc.in'
|
||||
static-pc-in: 'extism-static.pc.in'
|
||||
- os: 'ubuntu'
|
||||
target: 'x86_64-unknown-linux-gnu'
|
||||
artifact: 'libextism.so'
|
||||
static-artifact: 'libextism.a'
|
||||
pc-in: 'extism.pc.in'
|
||||
static-pc-in: 'extism-static.pc.in'
|
||||
- os: 'ubuntu'
|
||||
target: 'x86_64-unknown-linux-musl'
|
||||
artifact: ''
|
||||
static-artifact: 'libextism.a'
|
||||
pc-in: ''
|
||||
static-pc-in: 'extism-static.pc.in'
|
||||
- os: 'windows'
|
||||
target: 'x86_64-pc-windows-gnu'
|
||||
artifact: 'extism.dll'
|
||||
static-artifact: 'libextism.a'
|
||||
pc-in: 'extism.pc.in'
|
||||
static-pc-in: 'extism-static.pc.in'
|
||||
- os: 'windows'
|
||||
target: 'x86_64-pc-windows-msvc'
|
||||
artifact: 'extism.dll'
|
||||
static-artifact: 'extism.lib'
|
||||
pc-in: ''
|
||||
static-pc-in: ''
|
||||
|
||||
target:
|
||||
[
|
||||
aarch64-unknown-linux-gnu,
|
||||
aarch64-unknown-linux-musl,
|
||||
x86_64-unknown-linux-gnu,
|
||||
]
|
||||
# i686-unknown-linux-gnu,
|
||||
if: always()
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -85,68 +36,16 @@ jobs:
|
||||
override: true
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: "${{matrix.os}}-${{matrix.target}}"
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
cache-on-failure: "true"
|
||||
|
||||
- name: Build Target (${{ matrix.os }} ${{ matrix.target }})
|
||||
- name: Build Target (${{ matrix.target }})
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ matrix.os != 'windows' }}
|
||||
use-cross: true
|
||||
command: build
|
||||
args: --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}
|
||||
|
||||
- name: set extism-maturin version
|
||||
shell: bash
|
||||
run: |
|
||||
pyproject="$(cat extism-maturin/pyproject.toml)"
|
||||
version="${{ github.ref }}"
|
||||
if [[ "$version" = "refs/heads/main" ]]; then
|
||||
version="0.0.0-dev"
|
||||
else
|
||||
version="${version/refs\/tags\/v/}"
|
||||
fi
|
||||
|
||||
<<<"$pyproject" >extism-maturin/pyproject.toml sed -e 's/^version = "0.0.0.replaced-by-ci"/version = "'"$version"'"/g'
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Build wheels
|
||||
uses: PyO3/maturin-action@v1
|
||||
# maturin's cffi integration struggles with gnu headers on windows.
|
||||
# there's partial work towards fixing this in `extism-maturin/build.rs`, but it's
|
||||
# not sufficient to get it to work. omit it for now!
|
||||
if: ${{ matrix.target != 'x86_64-pc-windows-gnu' && matrix.target != 'aarch64-unknown-linux-gnu' }}
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
args: --release --out dist --find-interpreter -m extism-maturin/Cargo.toml
|
||||
sccache: 'true'
|
||||
manylinux: auto
|
||||
|
||||
- name: Build GNU Linux wheels
|
||||
uses: PyO3/maturin-action@v1
|
||||
# One of our deps, "ring", needs a newer sysroot than what "manylinux: auto" provides.
|
||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
args: --release --out dist --find-interpreter -m extism-maturin/Cargo.toml
|
||||
sccache: 'true'
|
||||
manylinux: 2_28
|
||||
|
||||
- name: Add pkg-config files except on MSVC
|
||||
if: ${{ matrix.target != 'x86_64-pc-windows-msvc' }}
|
||||
shell: bash
|
||||
run: |
|
||||
SRC_DIR=target/${{ matrix.target }}/release
|
||||
cp libextism/extism*.pc.in ${SRC_DIR}
|
||||
|
||||
- name: Prepare Artifact
|
||||
shell: bash
|
||||
run: |
|
||||
EXT=so
|
||||
SRC_DIR=target/${{ matrix.target }}/release
|
||||
DEST_DIR=${{ env.ARTIFACT_DIR }}
|
||||
RELEASE_NAME=libextism-${{ matrix.target }}-${{ github.ref_name }}
|
||||
@@ -156,62 +55,270 @@ jobs:
|
||||
# compress the shared library & create checksum
|
||||
cp runtime/extism.h ${SRC_DIR}
|
||||
cp LICENSE ${SRC_DIR}
|
||||
tar -C ${SRC_DIR} -czvf ${ARCHIVE} extism.h \
|
||||
${{ matrix.artifact }} ${{ matrix.static-artifact }} \
|
||||
${{ matrix.pc-in }} ${{ matrix.static-pc-in }}
|
||||
tar -C ${SRC_DIR} -czvf ${ARCHIVE} libextism.${EXT} extism.h
|
||||
ls -ll ${ARCHIVE}
|
||||
|
||||
if &>/dev/null which shasum; then
|
||||
shasum -a 256 ${ARCHIVE} > ${CHECKSUM}
|
||||
else
|
||||
# windows doesn't have shasum available, so we use certutil instead.
|
||||
certutil -hashfile ${ARCHIVE} SHA256 >${CHECKSUM}
|
||||
fi
|
||||
shasum -a 256 ${ARCHIVE} > ${CHECKSUM}
|
||||
|
||||
# copy archive and checksum into release artifact directory
|
||||
mkdir -p ${DEST_DIR}
|
||||
cp ${ARCHIVE} ${DEST_DIR}
|
||||
cp ${CHECKSUM} ${DEST_DIR}
|
||||
|
||||
# copy any built wheels.
|
||||
if [ -e dist/*.whl ]; then
|
||||
cp dist/*.whl ${DEST_DIR}
|
||||
fi
|
||||
|
||||
ls -ll ${DEST_DIR}
|
||||
ls ${DEST_DIR}
|
||||
|
||||
- name: Upload Artifact to Summary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_DIR }}
|
||||
path: ${{ env.ARTIFACT_DIR }}
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.txt
|
||||
|
||||
- name: Upload Artifact to Draft Release
|
||||
- name: Upload Artifact to Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: true
|
||||
files: |
|
||||
${{ env.ARTIFACT_DIR }}/*
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
||||
release-latest:
|
||||
name: create latest release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [release]
|
||||
if: github.ref == 'refs/heads/main'
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_DIR }}
|
||||
|
||||
- uses: "marvinpinto/action-automatic-releases@latest"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
automatic_release_tag: "latest"
|
||||
prerelease: true
|
||||
title: "Development Build"
|
||||
files: |
|
||||
*.tar.gz
|
||||
*.txt
|
||||
*.whl
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
release-macos:
|
||||
name: macos
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [x86_64-apple-darwin, aarch64-apple-darwin]
|
||||
if: always()
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Build Target (${{ matrix.target }})
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: true
|
||||
command: build
|
||||
args: --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}
|
||||
|
||||
- name: Prepare Artifact
|
||||
run: |
|
||||
EXT=dylib
|
||||
SRC_DIR=target/${{ matrix.target }}/release
|
||||
DEST_DIR=${{ env.ARTIFACT_DIR }}
|
||||
RELEASE_NAME=libextism-${{ matrix.target }}-${{ github.ref_name }}
|
||||
ARCHIVE=${RELEASE_NAME}.tar.gz
|
||||
CHECKSUM=${RELEASE_NAME}.checksum.txt
|
||||
|
||||
# compress the shared library & create checksum
|
||||
cp runtime/extism.h ${SRC_DIR}
|
||||
cp LICENSE ${SRC_DIR}
|
||||
tar -C ${SRC_DIR} -czvf ${ARCHIVE} libextism.${EXT} extism.h
|
||||
ls -ll ${ARCHIVE}
|
||||
shasum -a 256 ${ARCHIVE} > ${CHECKSUM}
|
||||
|
||||
# copy archive and checksum into release artifact directory
|
||||
mkdir -p ${DEST_DIR}
|
||||
cp ${ARCHIVE} ${DEST_DIR}
|
||||
cp ${CHECKSUM} ${DEST_DIR}
|
||||
|
||||
ls ${DEST_DIR}
|
||||
|
||||
- name: Upload Artifact to Summary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_DIR }}
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.txt
|
||||
|
||||
- name: Upload Artifact to Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
*.tar.gz
|
||||
*.txt
|
||||
|
||||
release-windows:
|
||||
name: windows
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target:
|
||||
[x86_64-pc-windows-gnu, x86_64-pc-windows-msvc]
|
||||
# i686-pc-windows-gnu,
|
||||
# i686-pc-windows-msvc,
|
||||
# aarch64-pc-windows-msvc
|
||||
if: always()
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Build Target (${{ matrix.target }})
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}
|
||||
|
||||
- name: Prepare Artifact
|
||||
shell: bash
|
||||
run: |
|
||||
EXT=dll
|
||||
SRC_DIR=target/${{ matrix.target }}/release
|
||||
DEST_DIR=${{ env.ARTIFACT_DIR }}
|
||||
RELEASE_NAME=libextism-${{ matrix.target }}-${{ github.ref_name }}
|
||||
ARCHIVE=${RELEASE_NAME}.tar.gz
|
||||
CHECKSUM=${RELEASE_NAME}.checksum.txt
|
||||
|
||||
# compress the shared library & create checksum
|
||||
cp runtime/extism.h ${SRC_DIR}
|
||||
cp LICENSE ${SRC_DIR}
|
||||
tar -C ${SRC_DIR} -czvf ${ARCHIVE} extism.${EXT} extism.h
|
||||
ls -ll ${ARCHIVE}
|
||||
|
||||
certutil -hashfile ${ARCHIVE} SHA256 >${CHECKSUM}
|
||||
|
||||
# copy archive and checksum into release artifact directory
|
||||
mkdir -p ${DEST_DIR}
|
||||
cp ${ARCHIVE} ${DEST_DIR}
|
||||
cp ${CHECKSUM} ${DEST_DIR}
|
||||
|
||||
ls ${DEST_DIR}
|
||||
|
||||
- name: Upload Artifact to Summary
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_DIR }}
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.txt
|
||||
|
||||
- name: Upload Artifact to Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
*.tar.gz
|
||||
*.txt
|
||||
|
||||
release-sdks:
|
||||
needs: [release-linux, release-macos] # release-windows
|
||||
name: publish-sdks
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node env
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_API_TOKEN }}
|
||||
CI: true
|
||||
|
||||
- name: Release Node Host SDK
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_API_TOKEN }}
|
||||
CI: true
|
||||
run: |
|
||||
cd node
|
||||
npm publish
|
||||
|
||||
- name: Setup Rust env
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
override: true
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Release Rust Host SDK
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
|
||||
run: |
|
||||
# order of crate publication matter: manifest, runtime, rust
|
||||
|
||||
cargo publish --manifest-path manifest/Cargo.toml
|
||||
# allow for crates.io to update so dependant crates can locate extism-manifest
|
||||
sleep 5
|
||||
|
||||
cargo publish --manifest-path runtime/Cargo.toml --no-verify
|
||||
cargo publish --manifest-path rust/Cargo.toml
|
||||
|
||||
- name: Setup Elixir Host SDK
|
||||
uses: erlef/setup-beam@v1
|
||||
with:
|
||||
experimental-otp: true
|
||||
otp-version: '25.0.4'
|
||||
elixir-version: '1.14.0'
|
||||
|
||||
- name: Publish Elixir Host SDK to hex.pm
|
||||
env:
|
||||
HEX_API_KEY: ${{ secrets.HEX_PM_API_TOKEN }}
|
||||
run: |
|
||||
cd elixir
|
||||
cp ../LICENSE .
|
||||
mix do deps.get, deps.compile
|
||||
mix hex.build
|
||||
mix hex.publish --yes
|
||||
|
||||
- name: Setup Ruby
|
||||
uses: actions/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '3.1' # Version range or exact version of a Ruby version to use, using semvers version range syntax.
|
||||
|
||||
- name: Publish Ruby Gem
|
||||
env:
|
||||
RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_TOKEN }}
|
||||
run: |
|
||||
cd ruby
|
||||
gem build extism.gemspec
|
||||
gem push extism*.gem -k $RUBYGEMS_API_KEY
|
||||
|
||||
- name: Publish Elixir Host SDK to hex.pm
|
||||
env:
|
||||
HEX_API_KEY: ${{ secrets.HEX_PM_API_TOKEN }}
|
||||
run: |
|
||||
cd elixir
|
||||
mix do deps.get, deps.compile
|
||||
mix hex.build
|
||||
mix hex.publish --yes
|
||||
|
||||
- name: Setup Python env
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.9"
|
||||
check-latest: true
|
||||
|
||||
- name: Build Python Host SDK
|
||||
run: |
|
||||
pushd python
|
||||
python3 -m pip install --upgrade build
|
||||
cp ../LICENSE .
|
||||
cp ../README.md .
|
||||
python3 -m poetry build
|
||||
popd
|
||||
|
||||
- name: Release Python Host SDK
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
env:
|
||||
INPUT_VERIFY_METADATA: false
|
||||
with:
|
||||
user: ${{ secrets.PYPI_API_USER }}
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||
packages_dir: python/dist/
|
||||
|
||||
23
.gitignore
vendored
23
.gitignore
vendored
@@ -13,10 +13,6 @@ __pycache__
|
||||
python/dist
|
||||
python/poetry.lock
|
||||
c/main
|
||||
cpp/test/test
|
||||
cpp/example
|
||||
.dub
|
||||
dub.selections.json
|
||||
go/main
|
||||
ruby/.bundle/
|
||||
ruby/.yardoc
|
||||
@@ -27,23 +23,12 @@ ruby/pkg/
|
||||
ruby/spec/reports/
|
||||
ruby/tmp/
|
||||
ruby/Gemfile.lock
|
||||
cpp/example
|
||||
rust/target
|
||||
rust/test.log
|
||||
duniverse
|
||||
_build
|
||||
ocaml/duniverse
|
||||
ocaml/_build
|
||||
php/Extism.php
|
||||
python/docs
|
||||
dist-newstyle
|
||||
.stack-work
|
||||
vendor
|
||||
zig/zig-*
|
||||
zig/example-out/
|
||||
zig/*.log
|
||||
java/*.iml
|
||||
java/*.log
|
||||
java/.idea
|
||||
java/.DS_Store
|
||||
extism-maturin/src/extism.h
|
||||
runtime/*.log
|
||||
libextism/example
|
||||
libextism/extism*.pc
|
||||
vendor
|
||||
@@ -1 +0,0 @@
|
||||
version = 0.26.0
|
||||
10
Cargo.toml
10
Cargo.toml
@@ -1,10 +1,10 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"extism-maturin",
|
||||
"manifest",
|
||||
"runtime",
|
||||
"libextism",
|
||||
"convert"
|
||||
"rust",
|
||||
]
|
||||
exclude = ["kernel"]
|
||||
exclude = [
|
||||
"elixir/native/extism_nif"
|
||||
]
|
||||
|
||||
|
||||
39
Makefile
39
Makefile
@@ -1,9 +1,7 @@
|
||||
DEST?=/usr/local
|
||||
SOEXT=so
|
||||
AEXT=a
|
||||
FEATURES?=default
|
||||
DEFAULT_FEATURES?=yes
|
||||
RUST_TARGET?=
|
||||
|
||||
UNAME := $(shell uname -s)
|
||||
ifeq ($(UNAME),Darwin)
|
||||
@@ -20,43 +18,20 @@ else
|
||||
FEATURE_FLAGS=--features $(FEATURES)
|
||||
endif
|
||||
|
||||
ifeq ($(RUST_TARGET),)
|
||||
TARGET_FLAGS=
|
||||
else
|
||||
TARGET_FLAGS=--target $(RUST_TARGET)
|
||||
endif
|
||||
|
||||
build:
|
||||
cargo build --release $(FEATURE_FLAGS) --manifest-path libextism/Cargo.toml $(TARGET_FLAGS)
|
||||
sed -e "s%@CMAKE_INSTALL_PREFIX@%$(DEST)%" libextism/extism.pc.in > libextism/extism.pc
|
||||
sed -e "s%@CMAKE_INSTALL_PREFIX@%$(DEST)%" libextism/extism-static.pc.in > libextism/extism-static.pc
|
||||
|
||||
bench:
|
||||
@(cargo criterion $(TARGET_FLAGS) || echo 'For nicer output use cargo-criterion: `cargo install cargo-criterion` - using `cargo bench`') && cargo bench $(TARGET_FLAGS)
|
||||
|
||||
.PHONY: kernel
|
||||
kernel:
|
||||
cd kernel && bash build.sh
|
||||
.PHONY: build
|
||||
|
||||
lint:
|
||||
cargo clippy --release --no-deps --manifest-path runtime/Cargo.toml $(TARGET_FLAGS)
|
||||
cargo clippy --release --no-deps --manifest-path runtime/Cargo.toml
|
||||
|
||||
debug:
|
||||
RUSTFLAGS=-g RUST_TARGET=$(RUST_TARGET) $(MAKE) build
|
||||
build:
|
||||
cargo build --release $(FEATURE_FLAGS) --manifest-path runtime/Cargo.toml
|
||||
|
||||
install:
|
||||
echo $(RUST_TARGET)
|
||||
mkdir -p $(DEST)/lib $(DEST)/include $(DEST)/lib/pkgconfig
|
||||
install runtime/extism.h $(DEST)/include/extism.h
|
||||
if [ -f target/$(RUST_TARGET)/release/libextism.$(SOEXT) ]; then \
|
||||
install target/$(RUST_TARGET)/release/libextism.$(SOEXT) $(DEST)/lib/libextism.$(SOEXT); \
|
||||
fi
|
||||
install target/$(RUST_TARGET)/release/libextism.$(AEXT) $(DEST)/lib/libextism.$(AEXT)
|
||||
install libextism/extism.pc $(DEST)/lib/pkgconfig/extism.pc
|
||||
install libextism/extism-static.pc $(DEST)/lib/pkgconfig/extism-static.pc
|
||||
install runtime/extism.h $(DEST)/include
|
||||
install target/release/libextism.$(SOEXT) $(DEST)/lib
|
||||
|
||||
uninstall:
|
||||
rm -f $(DEST)/include/extism.h $(DEST)/lib/libextism.$(SOEXT) $(DEST)/lib/libextism.$(AEXT) \
|
||||
$(DEST)/lib/pkgconfig/extism*.pc
|
||||
rm -f $(DEST)/include/extism.h $(DEST)/lib/libextism.$(SOEXT)
|
||||
|
||||
|
||||
|
||||
34
README.md
34
README.md
@@ -1,37 +1,23 @@
|
||||
### _Welcome!_
|
||||
|
||||
**Please note:** This project still under active development and APIs are changing as we hit 1.0. Currently, the main branch has many breaking changes. Our current release is 0.5.x. Until we release 1.0, we are cutting these releases from the [stable](https://github.com/extism/extism/tree/stable) branch.
|
||||
|
||||
If you're interested in working on or building with Extism, please join our [Discord](https://discord.gg/cx3usBCWnc) and let us know - we are happy to help get you started.
|
||||
**Please note:** this project still under active development. It's usable, but expect some rough edges while work is underway. If you're interested in working on or building with Extism, please join our [Discord](https://discord.gg/cx3usBCWnc) and let us know - we are happy to help get you started.
|
||||
|
||||
[](https://discord.gg/cx3usBCWnc)
|
||||
|
||||
# [Extism](https://extism.org)
|
||||
|
||||
The universal plug-in system. Run WebAssembly extensions inside your app. Use idiomatic Host SDKs for [Go](https://github.com/extism/go-sdk#readme),
|
||||
[Ruby](https://github.com/extism/ruby-sdk#readme),
|
||||
[Python](https://github.com/extism/python-sdk#readme),
|
||||
[JavaScript](https://github.com/extism/js-sdk#readme),
|
||||
[Rust](/runtime/#readme),
|
||||
[C](libextism/#readme),
|
||||
[C++](https://github.com/extism/cpp-sdk/#readme),
|
||||
[OCaml](https://github.com/extism/ocaml-sdk#readme),
|
||||
[Haskell](https://github.com/extism/haskell-sdk#readme),
|
||||
[PHP](https://github.com/extism/php-sdk#readme),
|
||||
[Elixir](https://github.com/extism/elixir-sdk#readme),
|
||||
[.NET](https://github.com/extism/dotnet-sdk#readme),
|
||||
[Java](https://github.com/extism/java-sdk#readme),
|
||||
[Zig](https://github.com/extism/zig-sdk#readme),
|
||||
[D](https://github.com/extism/d-sdk#readme),
|
||||
& more (others coming soon).
|
||||
The universal plug-in system. Run WebAssembly extensions inside your app. Use idiomatic Host SDKs for [Go](https://extism.org/docs/integrate-into-your-codebase/go-host-sdk),
|
||||
[Ruby](https://extism.org/docs/integrate-into-your-codebase/ruby-host-sdk), [Python](https://extism.org/docs/integrate-into-your-codebase/python-host-sdk),
|
||||
[Node](https://extism.org/docs/integrate-into-your-codebase/node-host-sdk), [Rust](https://extism.org/docs/integrate-into-your-codebase/rust-host-sdk),
|
||||
[C](https://extism.org/docs/integrate-into-your-codebase/c-host-sdk), [C++](https://extism.org/docs/integrate-into-your-codebase/cpp-host-sdk),
|
||||
[OCaml](https://extism.org/docs/integrate-into-your-codebase/ocaml-host-sdk), [Haskell](https://extism.org/docs/integrate-into-your-codebase/haskell-host-sdk), [PHP](https://extism.org/docs/integrate-into-your-codebase/php-host-sdk) & more (others coming soon).
|
||||
|
||||
Plug-in development kits (PDK) for plug-in authors supported in [Rust](https://github.com/extism/rust-pdk#readme), [AssemblyScript](https://github.com/extism/assemblyscript-pdk#readme), [Go](https://github.com/extism/go-pdk#readme), [C/C++](https://github.com/extism/c-pdk#readme), [Haskell](https://github.com/extism/haskell-pdk#readme), [JavaScript](https://github.com/extism/js-pdk#readme), [C#](https://github.com/extism/dotnet-pdk#readme), [F#](https://github.com/extism/dotnet-pdk#readme) and [Zig](https://github.com/extism/zig-pdk#readme).
|
||||
Plug-in development kits (PDK) for plug-in authors supported in [Rust](https://github.com/extism/rust-pdk), [AssemblyScript](https://github.com/extism/assemblyscript-pdk), [Go](https://github.com/extism/go-pdk), [C/C++](https://github.com/extism/c-pdk).
|
||||
|
||||
<p align="center">
|
||||
<img style="width: 70%;" src="https://user-images.githubusercontent.com/7517515/210286900-39b144fd-1b26-4dd0-b7a9-2b5755bc174d.png" alt="Extism embedded SDK language support"/>
|
||||
<img style="width: 70%;" src="https://user-images.githubusercontent.com/7517515/191437220-4030840d-1a9e-47b9-a44a-39a004885308.png"/>
|
||||
</p>
|
||||
|
||||
|
||||
Add a flexible, secure, and _bLaZiNg FaSt_ plug-in system to your project. Server, desktop, mobile, web, database -- you name it. Enable users to write and execute safe extensions to your software in **3 easy steps:**
|
||||
|
||||
### 1. Import
|
||||
@@ -65,8 +51,8 @@ The easiest way to start would be to join the [Discord](https://discord.gg/cx3us
|
||||
Extism is an open-source product from the team at:
|
||||
|
||||
<p align="left">
|
||||
<a href="https://dylib.so" _target="blanks"><img width="200px" src="https://user-images.githubusercontent.com/7517515/198204119-5afdebb9-a5d8-4322-bd2a-46179c8d7b24.svg"/></a>
|
||||
</p>
|
||||
<a href="https://dylib.so" _target="blanks"><img width="200px" src="https://user-images.githubusercontent.com/7517515/195408048-0f199b26-cba3-4635-b683-f43b1e610c82.svg"/></a>
|
||||
</p>![dylibso-logo-outline]
|
||||
|
||||
|
||||
_Reach out and tell us what you're building! We'd love to help._
|
||||
|
||||
130
browser/.gitignore
vendored
130
browser/.gitignore
vendored
@@ -1,130 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"trailingComma": "all",
|
||||
"singleQuote": true
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
.PHONY: test
|
||||
|
||||
prepare:
|
||||
npm install
|
||||
|
||||
build:
|
||||
npm run build
|
||||
|
||||
test: prepare
|
||||
npm run test
|
||||
|
||||
clean:
|
||||
echo "No clean implemented"
|
||||
|
||||
publish: clean prepare build
|
||||
npm publish
|
||||
|
||||
format:
|
||||
npx prettier --write src
|
||||
|
||||
lint:
|
||||
npx prettier --check src
|
||||
|
||||
docs:
|
||||
npx typedoc --out doc src
|
||||
|
||||
show-docs: docs
|
||||
open doc/index.html
|
||||
@@ -1,4 +0,0 @@
|
||||
# Browser Host SDK
|
||||
|
||||
This contains the `0.x` version of the SDK. This library is deprecated and all new integrations should use the new [Universal JavaScript library](https://github.com/extism/js-sdk#readme).
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
const { build } = require("esbuild");
|
||||
const { peerDependencies } = require('./package.json')
|
||||
|
||||
const sharedConfig = {
|
||||
entryPoints: ["src/index.ts"],
|
||||
bundle: true,
|
||||
minify: false,
|
||||
drop: [], // preseve debugger statements
|
||||
external: Object.keys(peerDependencies || {}),
|
||||
};
|
||||
|
||||
build({
|
||||
...sharedConfig,
|
||||
platform: 'node', // for CJS
|
||||
outfile: "dist/index.js",
|
||||
});
|
||||
|
||||
build({
|
||||
...sharedConfig,
|
||||
outfile: "dist/index.esm.js",
|
||||
platform: 'neutral', // for ESM
|
||||
format: "esm",
|
||||
});
|
||||
Binary file not shown.
@@ -1,248 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
|
||||
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
|
||||
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
|
||||
<style>
|
||||
#main {
|
||||
width: 100%;
|
||||
}
|
||||
.manifest {
|
||||
display: flex; /* or inline-flex */
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
width: 100%;
|
||||
}
|
||||
.urlInput {
|
||||
width: 600px;
|
||||
}
|
||||
.funcName {
|
||||
width: 150px;
|
||||
}
|
||||
.textAreas {
|
||||
display: flex; /* or inline-flex */
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
.inputBox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.inputBox > textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.outputBox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.outputBox > textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.space {
|
||||
height: 80px;
|
||||
}
|
||||
.dragAreas {
|
||||
display: flex; /* or inline-flex */
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
.dragInput {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-style: dotted;
|
||||
border-color: #000;
|
||||
}
|
||||
.dragOutput {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.dropZone {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.outputImage {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/babel">
|
||||
function getBase64(file, cb) {
|
||||
var reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = function () {
|
||||
cb(reader.result)
|
||||
};
|
||||
reader.onerror = function (error) {
|
||||
console.log("error")
|
||||
};
|
||||
}
|
||||
|
||||
function arrayTob64(buffer) {
|
||||
var binary = '';
|
||||
var bytes = [].slice.call(buffer);
|
||||
bytes.forEach((b) => binary += String.fromCharCode(b));
|
||||
return window.btoa(binary);
|
||||
}
|
||||
|
||||
|
||||
class App extends React.Component {
|
||||
state = {
|
||||
url: "https://raw.githubusercontent.com/extism/extism/main/wasm/code.wasm",
|
||||
input: new Uint8Array(),
|
||||
output: new Uint8Array(),
|
||||
func_name: "count_vowels",
|
||||
functions: []
|
||||
}
|
||||
|
||||
async loadFunctions(url) {
|
||||
let helloWorld = function(index){
|
||||
console.log("Hello, " + this.allocator.getString(index));
|
||||
return index;
|
||||
};
|
||||
let plugin = await this.extismContext.newPlugin({ "wasm": [ { "path": url } ] }, {"hello_world": helloWorld});
|
||||
let functions = Object.keys(await plugin.getExports())
|
||||
console.log("funcs ", functions)
|
||||
this.setState({functions})
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.loadFunctions(this.state.url)
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.extismContext = props.extismContext
|
||||
}
|
||||
|
||||
handleInputChange(e) {
|
||||
e.preventDefault();
|
||||
this.setState({ [e.target.name]: e.target.value })
|
||||
if (e.target.name === "url") {
|
||||
this.loadFunctions(e.target.value)
|
||||
}
|
||||
}
|
||||
|
||||
onInputKeyPress(e) {
|
||||
if (e.keyCode == 13 && e.shiftKey == true) {
|
||||
e.preventDefault()
|
||||
this.handleOnRun()
|
||||
}
|
||||
}
|
||||
|
||||
async handleOnRun(e) {
|
||||
e && e.preventDefault && e.preventDefault();
|
||||
let helloWorld = function(index){
|
||||
console.log("Hello, " + this.allocator.getString(index));
|
||||
return index;
|
||||
};
|
||||
let plugin = await this.extismContext.newPlugin({ "wasm": [ { "path": this.state.url } ] }, {
|
||||
"hello_world": helloWorld
|
||||
});
|
||||
let result = await plugin.call(this.state.func_name, this.state.input)
|
||||
let output = result
|
||||
this.setState({output})
|
||||
}
|
||||
|
||||
nop = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
handleDrop = e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
let files = [...e.dataTransfer.files];
|
||||
if (files && files.length == 1) {
|
||||
let file = files[0]
|
||||
console.log(file)
|
||||
file.arrayBuffer().then(b => {
|
||||
this.setState({input: new Uint8Array(b)})
|
||||
this.handleOnRun()
|
||||
})
|
||||
} else {
|
||||
throw Error("Only one file please")
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const funcOptions = this.state.functions.map(f => <option value={f}>{f}</option>)
|
||||
let image = null
|
||||
if (this.state.output) {
|
||||
image = <img src={`data:image/png;base64,${arrayTob64(this.state.output)}`}/>
|
||||
}
|
||||
|
||||
return <div className="app">
|
||||
<div className="manifest">
|
||||
<div>
|
||||
<label>WASM Url: </label>
|
||||
<input type="text" name="url" className="urlInput" value={this.state.url} onChange={this.handleInputChange.bind(this)} />
|
||||
</div>
|
||||
<div>
|
||||
<label>Function: </label>
|
||||
<select type="text" name="func_name" className="funcName" value={this.state.func_name} onChange={this.handleInputChange.bind(this)}>
|
||||
{funcOptions}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<button onClick={this.handleOnRun.bind(this)}>Run</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="textAreas">
|
||||
<div className="inputBox">
|
||||
<h3>Text Input</h3>
|
||||
<textarea name="input" value={this.state.input} onChange={this.handleInputChange.bind(this)} onKeyDown={this.onInputKeyPress.bind(this)}></textarea>
|
||||
</div>
|
||||
<div className="outputBox">
|
||||
<h3>Text Output</h3>
|
||||
<textarea name="output" value={new TextDecoder().decode(this.state.output)} ></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space" />
|
||||
<div className="dragAreas">
|
||||
<div className="dragInput">
|
||||
<h3>Image Input</h3>
|
||||
<div className="dropZone"
|
||||
onDrop={this.handleDrop.bind(this)}
|
||||
onDragOver={this.nop.bind(this)}
|
||||
onDragEnter={this.nop.bind(this)}
|
||||
onDragLeave={this.nop.bind(this)}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div className="dragOutput">
|
||||
<h3>Image Output</h3>
|
||||
<div className="outputImage">
|
||||
{image}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
window.App = App
|
||||
</script>
|
||||
|
||||
<script type="module">
|
||||
import {ExtismContext} from './dist/index.esm.js'
|
||||
const e = React.createElement;
|
||||
|
||||
window.onload = () => {
|
||||
const domContainer = document.getElementById('main');
|
||||
console.log(domContainer)
|
||||
const root = ReactDOM.createRoot(domContainer);
|
||||
const extismContext = new ExtismContext()
|
||||
root.render(e(App, {extismContext}));
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +0,0 @@
|
||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'jsdom',
|
||||
};
|
||||
14458
browser/package-lock.json
generated
14458
browser/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"name": "@extism/runtime-browser",
|
||||
"version": "0.3.1",
|
||||
"description": "Extism runtime in the browser",
|
||||
"scripts": {
|
||||
"build": "node build.js && tsc --emitDeclarationOnly --outDir dist",
|
||||
"format": "prettier --write \"src/**/*.ts\"",
|
||||
"lint": "tslint -p tsconfig.json",
|
||||
"test": "jest --config jest.config.js"
|
||||
},
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"files": [
|
||||
"dist/*"
|
||||
],
|
||||
"module": "dist/index.esm.js",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/src/index.d.ts",
|
||||
"author": "The Extism Authors <oss@extism.org>",
|
||||
"license": "BSD-3-Clause",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.2.2",
|
||||
"esbuild": "^0.15.13",
|
||||
"esbuild-jest": "^0.5.0",
|
||||
"jest": "^29.2.2",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"prettier": "^2.7.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typedoc": "^0.23.20",
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bjorn3/browser_wasi_shim": "^0.2.7"
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
type MemoryBlock = { offset: bigint; length: bigint };
|
||||
|
||||
export default class Allocator {
|
||||
currentIndex: bigint;
|
||||
active: Record<number, MemoryBlock>;
|
||||
freed: MemoryBlock[];
|
||||
memory: Uint8Array;
|
||||
|
||||
constructor(n: number) {
|
||||
this.currentIndex = BigInt(1);
|
||||
this.active = {};
|
||||
this.freed = [];
|
||||
this.memory = new Uint8Array(n);
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.currentIndex = BigInt(1);
|
||||
this.active = {};
|
||||
this.freed = [];
|
||||
}
|
||||
|
||||
alloc(length: bigint): bigint {
|
||||
for (var i = 0; i < this.freed.length; i++) {
|
||||
let block = this.freed[i];
|
||||
if (block.length === length) {
|
||||
this.active[Number(block.offset)] = block;
|
||||
this.freed.splice(i, 1);
|
||||
return block.offset;
|
||||
} else if (block.length > length + BigInt(64)) {
|
||||
const newBlock = { offset: block.offset, length };
|
||||
block.offset += length;
|
||||
block.length -= length;
|
||||
return newBlock.offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Resize memory if needed
|
||||
// TODO: put a limit on the memory size
|
||||
if (BigInt(this.memory.length) < this.currentIndex + length) {
|
||||
const tmp = new Uint8Array(Number(this.currentIndex + length + BigInt(64)));
|
||||
tmp.set(this.memory);
|
||||
this.memory = tmp;
|
||||
}
|
||||
|
||||
const offset = this.currentIndex;
|
||||
this.currentIndex += length;
|
||||
this.active[Number(offset)] = { offset, length };
|
||||
return offset;
|
||||
}
|
||||
|
||||
getBytes(offset: bigint): Uint8Array | null {
|
||||
const block = this.active[Number(offset)];
|
||||
if (!block) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Uint8Array(this.memory.buffer, Number(offset), Number(block.length));
|
||||
}
|
||||
|
||||
getString(offset: bigint): string | null {
|
||||
const bytes = this.getBytes(offset);
|
||||
if (bytes === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TextDecoder().decode(bytes);
|
||||
}
|
||||
|
||||
allocBytes(data: Uint8Array): bigint {
|
||||
const offs = this.alloc(BigInt(data.length));
|
||||
const bytes = this.getBytes(offs);
|
||||
if (bytes === null) {
|
||||
this.free(offs);
|
||||
return BigInt(0);
|
||||
}
|
||||
|
||||
bytes.set(data);
|
||||
return offs;
|
||||
}
|
||||
|
||||
allocString(data: string): bigint {
|
||||
const bytes = new TextEncoder().encode(data);
|
||||
return this.allocBytes(bytes);
|
||||
}
|
||||
|
||||
getLength(offset: bigint): bigint {
|
||||
const block = this.active[Number(offset)];
|
||||
if (!block) {
|
||||
return BigInt(0);
|
||||
}
|
||||
|
||||
return block.length;
|
||||
}
|
||||
|
||||
free(offset: bigint) {
|
||||
const block = this.active[Number(offset)];
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete this.active[Number(offset)];
|
||||
this.freed.push(block);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { Manifest, PluginConfig, ManifestWasmFile, ManifestWasmData } from './manifest';
|
||||
import { ExtismPlugin } from './plugin';
|
||||
|
||||
/**
|
||||
* Can be a {@link Manifest} or just the raw bytes of the WASM module as an ArrayBuffer.
|
||||
* We recommend using {@link Manifest}
|
||||
*/
|
||||
type ManifestData = Manifest | ArrayBuffer | WebAssembly.Module;
|
||||
|
||||
/**
|
||||
* A Context is needed to create plugins. The Context
|
||||
* is where your plugins live. Freeing the context
|
||||
* frees all of the plugins in its scope.
|
||||
*/
|
||||
export default class ExtismContext {
|
||||
/**
|
||||
* Create a plugin managed by this context
|
||||
*
|
||||
* @param manifest - The {@link ManifestData} describing the plugin code and config
|
||||
* @param config - Config details for the plugin
|
||||
* @returns A new Plugin scoped to this Context
|
||||
*/
|
||||
async newPlugin(manifest: ManifestData, functions: Record<string, any> = {}, config?: PluginConfig) {
|
||||
let moduleData: ArrayBuffer | WebAssembly.Module | null = null;
|
||||
if (manifest instanceof ArrayBuffer || manifest instanceof WebAssembly.Module) {
|
||||
moduleData = manifest;
|
||||
} else if ((manifest as Manifest).wasm) {
|
||||
const wasmData = (manifest as Manifest).wasm;
|
||||
if (wasmData.length > 1) throw Error('This runtime only supports one module in Manifest.wasm');
|
||||
const wasm = wasmData[0];
|
||||
if ((wasm as ManifestWasmData).data) {
|
||||
moduleData = (wasm as ManifestWasmData).data;
|
||||
} else if ((wasm as ManifestWasmFile).path) {
|
||||
const response = await fetch((wasm as ManifestWasmFile).path);
|
||||
moduleData = await response.arrayBuffer();
|
||||
console.dir(moduleData);
|
||||
}
|
||||
}
|
||||
if (!moduleData) {
|
||||
throw Error(`Unsure how to interpret manifest ${manifest}`);
|
||||
}
|
||||
|
||||
return new ExtismPlugin(moduleData, functions, config);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { ExtismContext } from './';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
function parse(bytes: Uint8Array): any {
|
||||
return JSON.parse(new TextDecoder().decode(bytes));
|
||||
}
|
||||
|
||||
describe('', () => {
|
||||
it('can load and call a plugin', async () => {
|
||||
// const data = fs.readFileSync(path.join(__dirname, '..', 'data', 'code.wasm'));
|
||||
// const ctx = new ExtismContext();
|
||||
// const plugin = await ctx.newPlugin({ wasm: [{ data: data }] });
|
||||
// const functions = await plugin.getExports();
|
||||
// expect(Object.keys(functions).filter((x) => !x.startsWith('__') && x !== 'memory')).toEqual(['count_vowels']);
|
||||
// let output = await plugin.call('count_vowels', 'this is a test');
|
||||
// expect(parse(output)).toEqual({ count: 4 });
|
||||
// output = await plugin.call('count_vowels', 'this is a test again');
|
||||
// expect(parse(output)).toEqual({ count: 7 });
|
||||
// output = await plugin.call('count_vowels', 'this is a test thrice');
|
||||
// expect(parse(output)).toEqual({ count: 6 });
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
import ExtismContext from './context';
|
||||
import { ExtismFunction, ExtismPlugin } from './plugin';
|
||||
|
||||
export { ExtismContext, ExtismFunction, ExtismPlugin };
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* Represents a path or url to a WASM module
|
||||
*/
|
||||
export type ManifestWasmFile = {
|
||||
path: string;
|
||||
name?: string;
|
||||
hash?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents the raw bytes of a WASM file loaded into memory
|
||||
*/
|
||||
export type ManifestWasmData = {
|
||||
data: Uint8Array;
|
||||
name?: string;
|
||||
hash?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* {@link ExtismPlugin} Config
|
||||
*/
|
||||
export type PluginConfig = Map<string, string>;
|
||||
|
||||
/**
|
||||
* The WASM to load as bytes or a path
|
||||
*/
|
||||
export type ManifestWasm = ManifestWasmFile | ManifestWasmData;
|
||||
|
||||
/**
|
||||
* The manifest which describes the {@link ExtismPlugin} code and
|
||||
* runtime constraints.
|
||||
*
|
||||
* @see [Extism > Concepts > Manifest](https://extism.org/docs/concepts/manifest)
|
||||
*/
|
||||
export type Manifest = {
|
||||
wasm: Array<ManifestWasm>;
|
||||
//memory?: ManifestMemory;
|
||||
config?: PluginConfig;
|
||||
allowed_hosts?: Array<string>;
|
||||
};
|
||||
@@ -1,217 +0,0 @@
|
||||
import Allocator from './allocator';
|
||||
import { PluginConfig } from './manifest';
|
||||
import { WASI, Fd } from '@bjorn3/browser_wasi_shim';
|
||||
|
||||
export type ExtismFunction = any;
|
||||
|
||||
export class ExtismPlugin {
|
||||
moduleData: ArrayBuffer | WebAssembly.Module;
|
||||
allocator: Allocator;
|
||||
config?: PluginConfig;
|
||||
vars: Record<string, Uint8Array>;
|
||||
input: Uint8Array;
|
||||
output: Uint8Array;
|
||||
module?: WebAssembly.WebAssemblyInstantiatedSource;
|
||||
functions: Record<string, ExtismFunction>;
|
||||
|
||||
constructor(moduleData: ArrayBuffer | WebAssembly.Module, functions: Record<string, ExtismFunction> = {}, config?: PluginConfig) {
|
||||
this.moduleData = moduleData;
|
||||
this.allocator = new Allocator(1024 * 1024);
|
||||
this.config = config;
|
||||
this.vars = {};
|
||||
this.input = new Uint8Array();
|
||||
this.output = new Uint8Array();
|
||||
this.functions = functions;
|
||||
}
|
||||
|
||||
async getExports(): Promise<WebAssembly.Exports> {
|
||||
const module = await this._instantiateModule();
|
||||
return module.instance.exports;
|
||||
}
|
||||
|
||||
async getImports(): Promise<WebAssembly.ModuleImportDescriptor[]> {
|
||||
const module = await this._instantiateModule();
|
||||
return WebAssembly.Module.imports(module.module);
|
||||
}
|
||||
|
||||
async getInstance(): Promise<WebAssembly.Instance> {
|
||||
const module = await this._instantiateModule();
|
||||
return module.instance;
|
||||
}
|
||||
|
||||
async call(func_name: string, input: Uint8Array | string): Promise<Uint8Array> {
|
||||
const module = await this._instantiateModule();
|
||||
|
||||
if (typeof input === 'string') {
|
||||
this.input = new TextEncoder().encode(input);
|
||||
} else if (input instanceof Uint8Array) {
|
||||
this.input = input;
|
||||
} else {
|
||||
throw new Error('input should be string or Uint8Array');
|
||||
}
|
||||
|
||||
this.allocator.reset();
|
||||
|
||||
let func = module.instance.exports[func_name];
|
||||
if (!func) {
|
||||
throw Error(`function does not exist ${func_name}`);
|
||||
}
|
||||
//@ts-ignore
|
||||
func();
|
||||
return this.output;
|
||||
}
|
||||
|
||||
async _instantiateModule(): Promise<WebAssembly.WebAssemblyInstantiatedSource> {
|
||||
if (this.module) {
|
||||
return this.module;
|
||||
}
|
||||
const environment = this.makeEnv();
|
||||
const args: Array<string> = [];
|
||||
const envVars: Array<string> = [];
|
||||
let fds: Fd[] = [
|
||||
// new XtermStdio(term), // stdin
|
||||
// new XtermStdio(term), // stdout
|
||||
// new XtermStdio(term), // stderr
|
||||
];
|
||||
let wasi = new WASI(args, envVars, fds);
|
||||
let env = {
|
||||
wasi_snapshot_preview1: wasi.wasiImport,
|
||||
env: environment,
|
||||
};
|
||||
|
||||
if (this.moduleData instanceof WebAssembly.Module) {
|
||||
const instance = new WebAssembly.Instance(this.moduleData, env);
|
||||
this.module = {
|
||||
instance,
|
||||
module: this.moduleData
|
||||
}
|
||||
//@ts-ignore
|
||||
wasi.inst = instance;
|
||||
}
|
||||
else {
|
||||
this.module = await WebAssembly.instantiate(this.moduleData, env);
|
||||
//@ts-ignore
|
||||
wasi.inst = this.module.instance;
|
||||
}
|
||||
if (!this.module) throw Error("Unable to instantiate module");
|
||||
|
||||
// normally we would call wasi.start here but it doesn't respect when there is
|
||||
// no _start function
|
||||
if (this.module.instance.exports._start) {
|
||||
//@ts-ignore
|
||||
this.module.instance.exports._start();
|
||||
}
|
||||
return this.module;
|
||||
}
|
||||
|
||||
makeEnv(): any {
|
||||
const plugin = this;
|
||||
var env: any = {
|
||||
extism_alloc(n: bigint): bigint {
|
||||
return plugin.allocator.alloc(n);
|
||||
},
|
||||
extism_free(n: bigint) {
|
||||
plugin.allocator.free(n);
|
||||
},
|
||||
extism_load_u8(n: bigint): number {
|
||||
return plugin.allocator.memory[Number(n)];
|
||||
},
|
||||
extism_load_u64(n: bigint): bigint {
|
||||
let cast = new DataView(plugin.allocator.memory.buffer, Number(n));
|
||||
return cast.getBigUint64(0, true);
|
||||
},
|
||||
extism_store_u8(offset: bigint, n: number) {
|
||||
plugin.allocator.memory[Number(offset)] = Number(n);
|
||||
},
|
||||
extism_store_u64(offset: bigint, n: bigint) {
|
||||
const tmp = new DataView(plugin.allocator.memory.buffer, Number(offset));
|
||||
tmp.setBigUint64(0, n, true);
|
||||
},
|
||||
extism_input_length(): bigint {
|
||||
return BigInt(plugin.input.length);
|
||||
},
|
||||
extism_input_load_u8(i: bigint): number {
|
||||
return plugin.input[Number(i)];
|
||||
},
|
||||
extism_input_load_u64(idx: bigint): bigint {
|
||||
let cast = new DataView(plugin.input.buffer, Number(idx));
|
||||
return cast.getBigUint64(0, true);
|
||||
},
|
||||
extism_output_set(offset: bigint, length: bigint) {
|
||||
const offs = Number(offset);
|
||||
const len = Number(length);
|
||||
plugin.output = plugin.allocator.memory.slice(offs, offs + len);
|
||||
},
|
||||
extism_error_set(i: bigint) {
|
||||
throw plugin.allocator.getString(i);
|
||||
},
|
||||
extism_config_get(i: bigint): bigint {
|
||||
if (typeof plugin.config === 'undefined') {
|
||||
return BigInt(0);
|
||||
}
|
||||
const key = plugin.allocator.getString(i);
|
||||
if (key === null) {
|
||||
return BigInt(0);
|
||||
}
|
||||
const value = plugin.config.get(key);
|
||||
if (typeof value === 'undefined') {
|
||||
return BigInt(0);
|
||||
}
|
||||
return plugin.allocator.allocString(value);
|
||||
},
|
||||
extism_var_get(i: bigint): bigint {
|
||||
const key = plugin.allocator.getString(i);
|
||||
if (key === null) {
|
||||
return BigInt(0);
|
||||
}
|
||||
const value = plugin.vars[key];
|
||||
if (typeof value === 'undefined') {
|
||||
return BigInt(0);
|
||||
}
|
||||
return plugin.allocator.allocBytes(value);
|
||||
},
|
||||
extism_var_set(n: bigint, i: bigint) {
|
||||
const key = plugin.allocator.getString(n);
|
||||
if (key === null) {
|
||||
return;
|
||||
}
|
||||
const value = plugin.allocator.getBytes(i);
|
||||
if (value === null) {
|
||||
return;
|
||||
}
|
||||
plugin.vars[key] = value;
|
||||
},
|
||||
extism_http_request(n: bigint, i: bigint): number {
|
||||
debugger;
|
||||
return 0;
|
||||
},
|
||||
extism_length(i: bigint): bigint {
|
||||
return plugin.allocator.getLength(i);
|
||||
},
|
||||
extism_log_warn(i: bigint) {
|
||||
const s = plugin.allocator.getString(i);
|
||||
console.warn(s);
|
||||
},
|
||||
extism_log_info(i: bigint) {
|
||||
const s = plugin.allocator.getString(i);
|
||||
console.log(s);
|
||||
},
|
||||
extism_log_debug(i: bigint) {
|
||||
const s = plugin.allocator.getString(i);
|
||||
console.debug(s);
|
||||
},
|
||||
extism_log_error(i: bigint) {
|
||||
const s = plugin.allocator.getString(i);
|
||||
console.error(s);
|
||||
},
|
||||
};
|
||||
|
||||
for (const [name, func] of Object.entries(this.functions)) {
|
||||
env[name] = function () {
|
||||
return func.apply(plugin, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2016",
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true
|
||||
},
|
||||
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"tslint:recommended",
|
||||
"tslint-config-prettier"
|
||||
]
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
build:
|
||||
clang -g -o main main.c -lextism -L .
|
||||
clang -o main main.c -lextism -L .
|
||||
60
c/main.c
Normal file
60
c/main.c
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "../runtime/extism.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
uint8_t *read_file(const char *filename, size_t *len) {
|
||||
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
if (fp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t length = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
uint8_t *data = malloc(length);
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(fread(data, 1, length, fp) == length);
|
||||
fclose(fp);
|
||||
|
||||
*len = length;
|
||||
return data;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 2) {
|
||||
fputs("Not enough arguments\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ExtismContext *ctx = extism_context_new();
|
||||
|
||||
size_t len = 0;
|
||||
uint8_t *data = read_file("../wasm/code.wasm", &len);
|
||||
ExtismPlugin plugin = extism_plugin_new(ctx, data, len, false);
|
||||
free(data);
|
||||
if (plugin < 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
assert(extism_plugin_call(ctx, plugin, "count_vowels", (uint8_t *)argv[1],
|
||||
strlen(argv[1])) == 0);
|
||||
ExtismSize out_len = extism_plugin_output_length(ctx, plugin);
|
||||
const uint8_t *output = extism_plugin_output_data(ctx, plugin);
|
||||
write(STDOUT_FILENO, output, out_len);
|
||||
write(STDOUT_FILENO, "\n", 1);
|
||||
|
||||
extism_plugin_free(ctx, plugin);
|
||||
extism_context_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,49 +1,50 @@
|
||||
{
|
||||
"name": "extism/extism",
|
||||
"description": "Make your software programmable. Run WebAssembly extensions in your app using the first off-the-shelf, universal plug-in system.",
|
||||
"license": "BSD-3-Clause",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"WebAssembly",
|
||||
"plugin-system",
|
||||
"runtime",
|
||||
"plug-in"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The Extism Authors",
|
||||
"email": "oss@extism.org",
|
||||
"homepage": "https://extism.org"
|
||||
"name": "extism/extism",
|
||||
"description": "Make your software programmable. Run WebAssembly extensions in your app using the first off-the-shelf, universal plug-in system.",
|
||||
"license": "BSD-3-Clause",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"WebAssembly",
|
||||
"plugin-system",
|
||||
"runtime",
|
||||
"plug-in"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The Extism Authors",
|
||||
"email": "oss@extism.org",
|
||||
"homepage": "https://extism.org"
|
||||
},
|
||||
{
|
||||
"name": "Dylibso, Inc.",
|
||||
"email": "oss@dylib.so",
|
||||
"homepage": "https://dylib.so"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.4 || ^8",
|
||||
"ircmaxell/ffime": "dev-master"
|
||||
},
|
||||
{
|
||||
"name": "Dylibso, Inc.",
|
||||
"email": "oss@dylib.so",
|
||||
"homepage": "https://dylib.so"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.4 || ^8",
|
||||
"ircmaxell/ffime": "dev-master"
|
||||
},
|
||||
"suggest": {},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Extism\\": "php/src/"
|
||||
"suggest": {},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Extism\\": "php/src/"
|
||||
},
|
||||
"files": [
|
||||
"php/src/Plugin.php",
|
||||
"php/src/generate.php",
|
||||
"php/src/extism.h"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"php/src/Context.php",
|
||||
"php/src/Plugin.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {},
|
||||
"scripts": {},
|
||||
"scripts-descriptions": {}
|
||||
"autoload-dev": {
|
||||
"psr-4": {}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {},
|
||||
"scripts": {},
|
||||
"scripts-descriptions": {}
|
||||
}
|
||||
24
composer.lock
generated
24
composer.lock
generated
@@ -12,12 +12,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ircmaxell/FFIMe.git",
|
||||
"reference": "431a3c13d9906b974d50b13bf8295097ea000c5e"
|
||||
"reference": "5f648f95ecf23262a2e58f4e4c9001bd1b5f9c98"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ircmaxell/FFIMe/zipball/431a3c13d9906b974d50b13bf8295097ea000c5e",
|
||||
"reference": "431a3c13d9906b974d50b13bf8295097ea000c5e",
|
||||
"url": "https://api.github.com/repos/ircmaxell/FFIMe/zipball/5f648f95ecf23262a2e58f4e4c9001bd1b5f9c98",
|
||||
"reference": "5f648f95ecf23262a2e58f4e4c9001bd1b5f9c98",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -50,7 +50,7 @@
|
||||
"issues": "https://github.com/ircmaxell/FFIMe/issues",
|
||||
"source": "https://github.com/ircmaxell/FFIMe/tree/master"
|
||||
},
|
||||
"time": "2023-04-03T00:43:12+00:00"
|
||||
"time": "2022-09-01T18:56:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ircmaxell/php-c-parser",
|
||||
@@ -58,12 +58,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ircmaxell/php-c-parser.git",
|
||||
"reference": "29e0223704e4ee00c66f43506f5f52db151b3517"
|
||||
"reference": "55e0a4fdf88d6e955d928860e1e107a68492c1cf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ircmaxell/php-c-parser/zipball/29e0223704e4ee00c66f43506f5f52db151b3517",
|
||||
"reference": "29e0223704e4ee00c66f43506f5f52db151b3517",
|
||||
"url": "https://api.github.com/repos/ircmaxell/php-c-parser/zipball/55e0a4fdf88d6e955d928860e1e107a68492c1cf",
|
||||
"reference": "55e0a4fdf88d6e955d928860e1e107a68492c1cf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -99,7 +99,7 @@
|
||||
"issues": "https://github.com/ircmaxell/php-c-parser/issues",
|
||||
"source": "https://github.com/ircmaxell/php-c-parser/tree/master"
|
||||
},
|
||||
"time": "2023-03-23T10:58:24+00:00"
|
||||
"time": "2022-08-27T17:37:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ircmaxell/php-object-symbolresolver",
|
||||
@@ -107,12 +107,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ircmaxell/php-object-symbolresolver.git",
|
||||
"reference": "dfe1b1aa6c15b198bdef50fff8485e98e89f2a09"
|
||||
"reference": "3734df2b22d7c8273ee6f6f2155fddde6056d057"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ircmaxell/php-object-symbolresolver/zipball/dfe1b1aa6c15b198bdef50fff8485e98e89f2a09",
|
||||
"reference": "dfe1b1aa6c15b198bdef50fff8485e98e89f2a09",
|
||||
"url": "https://api.github.com/repos/ircmaxell/php-object-symbolresolver/zipball/3734df2b22d7c8273ee6f6f2155fddde6056d057",
|
||||
"reference": "3734df2b22d7c8273ee6f6f2155fddde6056d057",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -144,7 +144,7 @@
|
||||
"issues": "https://github.com/ircmaxell/php-object-symbolresolver/issues",
|
||||
"source": "https://github.com/ircmaxell/php-object-symbolresolver/tree/master"
|
||||
},
|
||||
"time": "2022-09-15T18:21:50+00:00"
|
||||
"time": "2022-08-14T19:30:20+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
[package]
|
||||
name = "extism-convert"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
authors = ["The Extism Authors", "oss@extism.org"]
|
||||
license = "BSD-3-Clause"
|
||||
readme = "./README.md"
|
||||
homepage = "https://extism.org"
|
||||
repository = "https://github.com/extism/extism"
|
||||
description = "Traits to make Rust types usable with Extism"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
base64 = "0.21.3"
|
||||
prost = { version = "0.12.0", optional = true }
|
||||
rmp-serde = { version = "1.1.2", optional = true }
|
||||
serde = "1.0.186"
|
||||
serde_json = "1.0.105"
|
||||
|
||||
[dev-dependencies]
|
||||
serde = {version = "1.0.186", features = ["derive"]}
|
||||
|
||||
[features]
|
||||
default = ["msgpack", "protobuf"]
|
||||
msgpack = ["rmp-serde"]
|
||||
protobuf = ["prost"]
|
||||
@@ -1,12 +0,0 @@
|
||||
# extism-convert
|
||||
|
||||
The [extism-convert](https://crates.io/crates/extism-convert) crate is used by the [Rust SDK](https://crates.io/crates/extism) and [Rust PDK](https://crates.io/crates/extism-pdk) to provide a shared interface for
|
||||
encoding and decoding values that can be passed to Extism function calls.
|
||||
|
||||
A set of types (Json, Msgpack, Protobuf) that can be used to specify a serde encoding are also provided. These are
|
||||
similar to [axum extractors](https://docs.rs/axum/latest/axum/extract/index.html#intro) - they are
|
||||
implemented as a tuple struct with a single field that is meant to be extracted using pattern matching.
|
||||
|
||||
## Documentation
|
||||
|
||||
See [extism-convert on docs.rs](https://docs.rs/extism-convert/latest/extism_convert/) for in-depth documentation.
|
||||
@@ -1,118 +0,0 @@
|
||||
use crate::*;
|
||||
|
||||
use base64::Engine;
|
||||
|
||||
/// The `encoding` macro can be used to create newtypes that implement a particular encoding for the
|
||||
/// inner value.
|
||||
///
|
||||
/// For example, the following line creates a new JSON encoding using serde_json:
|
||||
///
|
||||
/// ```
|
||||
/// extism_convert::encoding!(MyJson, serde_json::to_vec, serde_json::from_slice);
|
||||
/// ```
|
||||
///
|
||||
/// This will create a struct `struct MyJson<T>(pub T)` and implement `ToBytes` using `serde_json::to_vec`
|
||||
/// and `FromBytesOwned` using `serde_json::from_vec`
|
||||
#[macro_export]
|
||||
macro_rules! encoding {
|
||||
($name:ident, $to_vec:expr, $from_slice:expr) => {
|
||||
#[doc = concat!(stringify!($name), " encoding")]
|
||||
pub struct $name<T>(pub T);
|
||||
|
||||
impl<T> $name<T> {
|
||||
pub fn into_inner(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: serde::de::DeserializeOwned> $crate::FromBytesOwned for $name<T> {
|
||||
fn from_bytes_owned(data: &[u8]) -> std::result::Result<Self, $crate::Error> {
|
||||
let x = $from_slice(data)?;
|
||||
std::result::Result::Ok($name(x))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: serde::Serialize> $crate::ToBytes<'a> for $name<T> {
|
||||
type Bytes = Vec<u8>;
|
||||
|
||||
fn to_bytes(&self) -> std::result::Result<Self::Bytes, $crate::Error> {
|
||||
let enc = $to_vec(&self.0)?;
|
||||
std::result::Result::Ok(enc)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
encoding!(Json, serde_json::to_vec, serde_json::from_slice);
|
||||
|
||||
#[cfg(feature = "msgpack")]
|
||||
encoding!(Msgpack, rmp_serde::to_vec, rmp_serde::from_slice);
|
||||
|
||||
impl<'a> ToBytes<'a> for serde_json::Value {
|
||||
type Bytes = Vec<u8>;
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(serde_json::to_vec(self)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for serde_json::Value {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(serde_json::from_slice(data)?)
|
||||
}
|
||||
}
|
||||
|
||||
/// Base64 conversion
|
||||
///
|
||||
/// When using `Base64` with `ToBytes` any type that implement `AsRef<[T]>` may be used as the inner value,
|
||||
/// but only `Base64<String>` and `Base64<Vec>` may be used with `FromBytes`
|
||||
///
|
||||
/// A value wrapped in `Base64` will automatically be encoded/decoded using base64, the inner value should not
|
||||
/// already be base64 encoded.
|
||||
pub struct Base64<T: AsRef<[u8]>>(pub T);
|
||||
|
||||
impl<'a, T: AsRef<[u8]>> ToBytes<'a> for Base64<T> {
|
||||
type Bytes = String;
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(base64::engine::general_purpose::STANDARD.encode(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for Base64<Vec<u8>> {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Base64(
|
||||
base64::engine::general_purpose::STANDARD.decode(data)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for Base64<String> {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Base64(String::from_utf8(
|
||||
base64::engine::general_purpose::STANDARD.decode(data)?,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Protobuf encoding
|
||||
///
|
||||
/// Allows for `prost` Protobuf messages to be used as arguments to Extism plugin calls
|
||||
#[cfg(feature = "protobuf")]
|
||||
pub struct Protobuf<T: prost::Message>(pub T);
|
||||
|
||||
#[cfg(feature = "protobuf")]
|
||||
impl<'a, T: prost::Message> ToBytes<'a> for Protobuf<T> {
|
||||
type Bytes = Vec<u8>;
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self.0.encode_to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "protobuf")]
|
||||
impl<T: Default + prost::Message> FromBytesOwned for Protobuf<T> {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Protobuf(T::decode(data)?))
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
use crate::*;
|
||||
|
||||
/// `FromBytes` is used to define how a type should be decoded when working with
|
||||
/// Extism memory. It is used for plugin output and host function input.
|
||||
pub trait FromBytes<'a>: Sized {
|
||||
/// Decode a value from a slice of bytes
|
||||
fn from_bytes(data: &'a [u8]) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
/// `FromBytesOwned` is similar to `FromBytes` but it doesn't borrow from the input slice.
|
||||
/// `FromBytes` is automatically implemented for all types that implement `FromBytesOwned`
|
||||
pub trait FromBytesOwned: Sized {
|
||||
/// Decode a value from a slice of bytes, the resulting value should not borrow the input
|
||||
/// data.
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
impl<'a> FromBytes<'a> for &'a [u8] {
|
||||
fn from_bytes(data: &'a [u8]) -> Result<Self, Error> {
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromBytes<'a> for &'a str {
|
||||
fn from_bytes(data: &'a [u8]) -> Result<Self, Error> {
|
||||
Ok(std::str::from_utf8(data)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromBytesOwned> FromBytes<'a> for T {
|
||||
fn from_bytes(data: &'a [u8]) -> Result<Self, Error> {
|
||||
T::from_bytes_owned(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for Box<[u8]> {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(data.to_vec().into_boxed_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for Vec<u8> {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(data.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for String {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(std::str::from_utf8(data)?.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for f64 {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self::from_le_bytes(data.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for f32 {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self::from_le_bytes(data.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for i64 {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self::from_le_bytes(data.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for i32 {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self::from_le_bytes(data.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for u64 {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self::from_le_bytes(data.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for u32 {
|
||||
fn from_bytes_owned(data: &[u8]) -> Result<Self, Error> {
|
||||
Ok(Self::from_le_bytes(data.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromBytesOwned for () {
|
||||
fn from_bytes_owned(_: &[u8]) -> Result<Self, Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromBytes<'a>> FromBytes<'a> for std::io::Cursor<T> {
|
||||
fn from_bytes(data: &'a [u8]) -> Result<Self, Error> {
|
||||
Ok(std::io::Cursor::new(T::from_bytes(data)?))
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
//! The [extism-convert](https://crates.io/crates/extism-convert) crate is used by the [Rust SDK](https://crates.io/crates/extism) and [Rust PDK](https://crates.io/crates/extism-pdk) to provide a shared interface for
|
||||
//! encoding and decoding values that can be passed to Extism function calls.
|
||||
//!
|
||||
//! A set of types (Json, Msgpack) that can be used to specify a serde encoding are also provided. These are
|
||||
//! similar to [axum extractors](https://docs.rs/axum/latest/axum/extract/index.html#intro) - they are
|
||||
//! implemented as a tuple struct with a single field that is meant to be extracted using pattern matching.
|
||||
|
||||
pub use anyhow::Error;
|
||||
|
||||
mod encoding;
|
||||
|
||||
mod from_bytes;
|
||||
mod memory_handle;
|
||||
mod to_bytes;
|
||||
|
||||
pub use encoding::{Base64, Json};
|
||||
|
||||
#[cfg(feature = "msgpack")]
|
||||
pub use encoding::Msgpack;
|
||||
|
||||
#[cfg(feature = "protobuf")]
|
||||
pub use encoding::Protobuf;
|
||||
|
||||
pub use from_bytes::{FromBytes, FromBytesOwned};
|
||||
pub use memory_handle::MemoryHandle;
|
||||
pub use to_bytes::ToBytes;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -1,42 +0,0 @@
|
||||
/// `MemoryHandle` describes where in memory a block of data is stored
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
|
||||
pub struct MemoryHandle {
|
||||
/// The offset of the region in Extism linear memory
|
||||
pub offset: u64,
|
||||
|
||||
/// The length of the memory region
|
||||
pub length: u64,
|
||||
}
|
||||
|
||||
impl MemoryHandle {
|
||||
/// Create a new `MemoryHandle` from an offset in memory and length
|
||||
///
|
||||
/// # Safety
|
||||
/// This function is unsafe because the specified memory region may not be valid.
|
||||
pub unsafe fn new(offset: u64, length: u64) -> MemoryHandle {
|
||||
MemoryHandle { offset, length }
|
||||
}
|
||||
|
||||
/// `NULL` equivalent
|
||||
pub fn null() -> MemoryHandle {
|
||||
MemoryHandle {
|
||||
offset: 0,
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the offset of a memory handle
|
||||
pub fn offset(&self) -> u64 {
|
||||
self.offset
|
||||
}
|
||||
|
||||
/// Get the length of the memory region
|
||||
pub fn len(&self) -> usize {
|
||||
self.length as usize
|
||||
}
|
||||
|
||||
/// Returns `true` when the length is 0
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.length == 0
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
use crate::*;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
|
||||
struct Testing {
|
||||
a: String,
|
||||
b: i64,
|
||||
c: f32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_json() {
|
||||
let x = Testing {
|
||||
a: "foobar".to_string(),
|
||||
b: 123,
|
||||
c: 456.7,
|
||||
};
|
||||
let bytes = Json(&x).to_bytes().unwrap();
|
||||
let Json(y): Json<Testing> = FromBytes::from_bytes(&bytes).unwrap();
|
||||
assert_eq!(x, y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_msgpack() {
|
||||
let x = Testing {
|
||||
a: "foobar".to_string(),
|
||||
b: 123,
|
||||
c: 456.7,
|
||||
};
|
||||
let bytes = Msgpack(&x).to_bytes().unwrap();
|
||||
let Msgpack(y): Msgpack<Testing> = FromBytes::from_bytes(&bytes).unwrap();
|
||||
assert_eq!(x, y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_base64() {
|
||||
let bytes = Base64("this is a test").to_bytes().unwrap();
|
||||
let Base64(s): Base64<String> = FromBytes::from_bytes(bytes.as_bytes()).unwrap();
|
||||
assert_eq!(s, "this is a test");
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
use crate::*;
|
||||
|
||||
/// `ToBytes` is used to define how a type should be encoded when working with
|
||||
/// Extism memory. It is used for plugin input and host function output.
|
||||
pub trait ToBytes<'a> {
|
||||
/// A configurable byte slice representation, allows any type that implements `AsRef<[u8]>`
|
||||
type Bytes: AsRef<[u8]>;
|
||||
|
||||
/// `to_bytes` converts a value into `Self::Bytes`
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error>;
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for () {
|
||||
type Bytes = [u8; 0];
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok([])
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for Vec<u8> {
|
||||
type Bytes = Vec<u8>;
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for String {
|
||||
type Bytes = String;
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for &'a [u8] {
|
||||
type Bytes = &'a [u8];
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for &'a str {
|
||||
type Bytes = &'a str;
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for f64 {
|
||||
type Bytes = [u8; 8];
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for f32 {
|
||||
type Bytes = [u8; 4];
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for i64 {
|
||||
type Bytes = [u8; 8];
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for i32 {
|
||||
type Bytes = [u8; 4];
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for u64 {
|
||||
type Bytes = [u8; 8];
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToBytes<'a> for u32 {
|
||||
type Bytes = [u8; 4];
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
Ok(self.to_le_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ToBytes<'a>> ToBytes<'a> for &'a T {
|
||||
type Bytes = T::Bytes;
|
||||
|
||||
fn to_bytes(&self) -> Result<Self::Bytes, Error> {
|
||||
<T as ToBytes>::to_bytes(self)
|
||||
}
|
||||
}
|
||||
17
cpp/Makefile
17
cpp/Makefile
@@ -1,16 +1,3 @@
|
||||
FLAGS=`pkg-config --cflags --libs jsoncpp gtest` -lextism -lpthread
|
||||
|
||||
build-example:
|
||||
$(CXX) -std=c++14 -o example -I. example.cpp $(FLAGS)
|
||||
|
||||
.PHONY: example
|
||||
example: build-example
|
||||
./example
|
||||
|
||||
build-test:
|
||||
$(CXX) -std=c++14 -o test/test -I. test/test.cpp $(FLAGS)
|
||||
|
||||
.PHONY: test
|
||||
test: build-test
|
||||
cd test && ./test
|
||||
build:
|
||||
clang++ -std=c++11 -o example example.cpp -lextism -L .
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#define EXTISM_NO_JSON
|
||||
#include "extism.hpp"
|
||||
|
||||
#include <cstring>
|
||||
@@ -14,26 +13,10 @@ std::vector<uint8_t> read(const char *filename) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
auto wasm = read("../wasm/code-functions.wasm");
|
||||
std::string tmp = "Testing";
|
||||
auto wasm = read("../wasm/code.wasm");
|
||||
Context context = Context();
|
||||
|
||||
// A lambda can be used as a host function
|
||||
auto hello_world = [&tmp](CurrentPlugin plugin,
|
||||
const std::vector<Val> &inputs,
|
||||
std::vector<Val> &outputs, void *user_data) {
|
||||
std::cout << "Hello from C++" << std::endl;
|
||||
std::cout << (const char *)user_data << std::endl;
|
||||
std::cout << tmp << std::endl;
|
||||
outputs[0].v = inputs[0].v;
|
||||
};
|
||||
|
||||
std::vector<Function> functions = {
|
||||
Function("hello_world", {ValType::I64}, {ValType::I64}, hello_world,
|
||||
(void *)"Hello again!",
|
||||
[](void *x) { std::cout << "Free user data" << std::endl; }),
|
||||
};
|
||||
|
||||
Plugin plugin(wasm, true, functions);
|
||||
Plugin plugin = context.plugin(wasm);
|
||||
|
||||
const char *input = argc > 1 ? argv[1] : "this is a test";
|
||||
ExtismSize length = strlen(input);
|
||||
|
||||
450
cpp/extism.hpp
450
cpp/extism.hpp
@@ -1,205 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifndef EXTISM_NO_JSON
|
||||
#if __has_include(<jsoncpp/json/json.h>)
|
||||
#include <jsoncpp/json/json.h>
|
||||
#else
|
||||
#include <json/json.h>
|
||||
#endif
|
||||
#endif // EXTISM_NO_JSON
|
||||
|
||||
extern "C" {
|
||||
#include <extism.h>
|
||||
}
|
||||
|
||||
namespace extism {
|
||||
|
||||
typedef std::map<std::string, std::string> Config;
|
||||
|
||||
template <typename T> class ManifestKey {
|
||||
bool is_set = false;
|
||||
class Error : public std::exception {
|
||||
private:
|
||||
std::string message;
|
||||
|
||||
public:
|
||||
T value;
|
||||
ManifestKey(T x, bool is_set = false) : is_set(is_set) { value = x; }
|
||||
|
||||
void set(T x) {
|
||||
value = x;
|
||||
is_set = true;
|
||||
}
|
||||
|
||||
bool empty() const { return is_set == false; }
|
||||
};
|
||||
|
||||
class Wasm {
|
||||
std::string _path;
|
||||
std::string _url;
|
||||
// TODO: add base64 encoded raw data
|
||||
ManifestKey<std::string> _hash =
|
||||
ManifestKey<std::string>(std::string(), false);
|
||||
|
||||
public:
|
||||
// Create Wasm pointing to a path
|
||||
static Wasm path(std::string s, std::string hash = std::string()) {
|
||||
Wasm w;
|
||||
w._path = s;
|
||||
if (!hash.empty()) {
|
||||
w._hash.set(hash);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
// Create Wasm pointing to a URL
|
||||
static Wasm url(std::string s, std::string hash = std::string()) {
|
||||
Wasm w;
|
||||
w._url = s;
|
||||
if (!hash.empty()) {
|
||||
w._hash.set(hash);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
#ifndef EXTISM_NO_JSON
|
||||
Json::Value json() const {
|
||||
Json::Value doc;
|
||||
|
||||
if (!this->_path.empty()) {
|
||||
doc["path"] = this->_path;
|
||||
} else if (!this->_url.empty()) {
|
||||
doc["url"] = this->_url;
|
||||
}
|
||||
|
||||
if (!this->_hash.empty()) {
|
||||
doc["hash"] = this->_hash.value;
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class Manifest {
|
||||
public:
|
||||
Config config;
|
||||
std::vector<Wasm> wasm;
|
||||
ManifestKey<std::vector<std::string>> allowed_hosts;
|
||||
ManifestKey<std::map<std::string, std::string>> allowed_paths;
|
||||
ManifestKey<uint64_t> timeout_ms;
|
||||
|
||||
// Empty manifest
|
||||
Manifest()
|
||||
: timeout_ms(0, false), allowed_hosts(std::vector<std::string>(), false),
|
||||
allowed_paths(std::map<std::string, std::string>(), false) {}
|
||||
|
||||
// Create manifest with a single Wasm from a path
|
||||
static Manifest path(std::string s, std::string hash = std::string()) {
|
||||
Manifest m;
|
||||
m.add_wasm_path(s, hash);
|
||||
return m;
|
||||
}
|
||||
|
||||
// Create manifest with a single Wasm from a URL
|
||||
static Manifest url(std::string s, std::string hash = std::string()) {
|
||||
Manifest m;
|
||||
m.add_wasm_url(s, hash);
|
||||
return m;
|
||||
}
|
||||
|
||||
#ifndef EXTISM_NO_JSON
|
||||
std::string json() const {
|
||||
Json::Value doc;
|
||||
Json::Value wasm;
|
||||
for (auto w : this->wasm) {
|
||||
wasm.append(w.json());
|
||||
}
|
||||
|
||||
doc["wasm"] = wasm;
|
||||
|
||||
if (!this->config.empty()) {
|
||||
Json::Value conf;
|
||||
|
||||
for (auto k : this->config) {
|
||||
conf[k.first] = k.second;
|
||||
}
|
||||
doc["config"] = conf;
|
||||
}
|
||||
|
||||
if (!this->allowed_hosts.empty()) {
|
||||
Json::Value h;
|
||||
|
||||
for (auto s : this->allowed_hosts.value) {
|
||||
h.append(s);
|
||||
}
|
||||
doc["allowed_hosts"] = h;
|
||||
}
|
||||
|
||||
if (!this->allowed_paths.empty()) {
|
||||
Json::Value h;
|
||||
for (auto k : this->allowed_paths.value) {
|
||||
h[k.first] = k.second;
|
||||
}
|
||||
doc["allowed_paths"] = h;
|
||||
}
|
||||
|
||||
if (!this->timeout_ms.empty()) {
|
||||
doc["timeout_ms"] = Json::Value(this->timeout_ms.value);
|
||||
}
|
||||
|
||||
Json::FastWriter writer;
|
||||
return writer.write(doc);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Add Wasm from path
|
||||
void add_wasm_path(std::string s, std::string hash = std::string()) {
|
||||
Wasm w = Wasm::path(s, hash);
|
||||
this->wasm.push_back(w);
|
||||
}
|
||||
|
||||
// Add Wasm from URL
|
||||
void add_wasm_url(std::string u, std::string hash = std::string()) {
|
||||
Wasm w = Wasm::url(u, hash);
|
||||
this->wasm.push_back(w);
|
||||
}
|
||||
|
||||
// Add host to allowed hosts
|
||||
void allow_host(std::string host) {
|
||||
if (this->allowed_hosts.empty()) {
|
||||
this->allowed_hosts.set(std::vector<std::string>{});
|
||||
}
|
||||
this->allowed_hosts.value.push_back(host);
|
||||
}
|
||||
|
||||
// Add path to allowed paths
|
||||
void allow_path(std::string src, std::string dest = std::string()) {
|
||||
if (this->allowed_paths.empty()) {
|
||||
this->allowed_paths.set(std::map<std::string, std::string>{});
|
||||
}
|
||||
|
||||
if (dest.empty()) {
|
||||
dest = src;
|
||||
}
|
||||
this->allowed_paths.value[src] = dest;
|
||||
}
|
||||
|
||||
// Set timeout
|
||||
void set_timeout_ms(uint64_t ms) { this->timeout_ms = ms; }
|
||||
|
||||
// Set config key/value
|
||||
void set_config(std::string k, std::string v) { this->config[k] = v; }
|
||||
};
|
||||
|
||||
class Error : public std::runtime_error {
|
||||
public:
|
||||
Error(std::string msg) : std::runtime_error(msg) {}
|
||||
Error(std::string msg) : message(msg) {}
|
||||
const char *what() { return message.c_str(); }
|
||||
};
|
||||
|
||||
class Buffer {
|
||||
@@ -208,216 +24,48 @@ public:
|
||||
const uint8_t *data;
|
||||
ExtismSize length;
|
||||
|
||||
std::string string() { return (std::string)(*this); }
|
||||
|
||||
std::vector<uint8_t> vector() { return (std::vector<uint8_t>)(*this); }
|
||||
|
||||
operator std::string() { return std::string((const char *)data, length); }
|
||||
operator std::vector<uint8_t>() {
|
||||
return std::vector<uint8_t>(data, data + length);
|
||||
}
|
||||
};
|
||||
|
||||
typedef ExtismValType ValType;
|
||||
typedef ExtismValUnion ValUnion;
|
||||
typedef ExtismVal Val;
|
||||
typedef uint64_t MemoryHandle;
|
||||
|
||||
class CurrentPlugin {
|
||||
ExtismCurrentPlugin *pointer;
|
||||
|
||||
public:
|
||||
CurrentPlugin(ExtismCurrentPlugin *p) : pointer(p) {}
|
||||
|
||||
uint8_t *memory() { return extism_current_plugin_memory(this->pointer); }
|
||||
uint8_t *memory(MemoryHandle offs) { return this->memory() + offs; }
|
||||
|
||||
ExtismSize memoryLength(MemoryHandle offs) {
|
||||
return extism_current_plugin_memory_length(this->pointer, offs);
|
||||
}
|
||||
|
||||
MemoryHandle alloc(ExtismSize size) {
|
||||
return extism_current_plugin_memory_alloc(this->pointer, size);
|
||||
}
|
||||
|
||||
void free(MemoryHandle handle) {
|
||||
extism_current_plugin_memory_free(this->pointer, handle);
|
||||
}
|
||||
|
||||
void returnString(Val &output, const std::string &s) {
|
||||
this->returnBytes(output, (const uint8_t *)s.c_str(), s.size());
|
||||
}
|
||||
|
||||
void returnBytes(Val &output, const uint8_t *bytes, size_t len) {
|
||||
auto offs = this->alloc(len);
|
||||
memcpy(this->memory() + offs, bytes, len);
|
||||
output.v.i64 = offs;
|
||||
}
|
||||
|
||||
uint8_t *inputBytes(Val &inp, size_t *length = nullptr) {
|
||||
if (inp.t != ValType::I64) {
|
||||
return nullptr;
|
||||
}
|
||||
if (length != nullptr) {
|
||||
*length = this->memoryLength(inp.v.i64);
|
||||
}
|
||||
return this->memory() + inp.v.i64;
|
||||
}
|
||||
|
||||
std::string inputString(Val &inp) {
|
||||
size_t length = 0;
|
||||
char *buf = (char *)this->inputBytes(inp, &length);
|
||||
return std::string(buf, length);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::function<void(CurrentPlugin, const std::vector<Val> &,
|
||||
std::vector<Val> &, void *user_data)>
|
||||
FunctionType;
|
||||
|
||||
struct UserData {
|
||||
FunctionType func;
|
||||
void *user_data = NULL;
|
||||
std::function<void(void *)> free_user_data;
|
||||
};
|
||||
|
||||
static void function_callback(ExtismCurrentPlugin *plugin,
|
||||
const ExtismVal *inputs, ExtismSize n_inputs,
|
||||
ExtismVal *outputs, ExtismSize n_outputs,
|
||||
void *user_data) {
|
||||
UserData *data = (UserData *)user_data;
|
||||
const std::vector<Val> inp(inputs, inputs + n_inputs);
|
||||
std::vector<Val> outp(outputs, outputs + n_outputs);
|
||||
data->func(CurrentPlugin(plugin), inp, outp, data->user_data);
|
||||
|
||||
for (ExtismSize i = 0; i < n_outputs; i++) {
|
||||
outputs[i] = outp[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void free_user_data(void *user_data) {
|
||||
UserData *data = (UserData *)user_data;
|
||||
if (data->user_data != NULL && data->free_user_data != NULL) {
|
||||
data->free_user_data(data->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
class Function {
|
||||
std::shared_ptr<ExtismFunction> func;
|
||||
std::string name;
|
||||
UserData user_data;
|
||||
|
||||
public:
|
||||
Function(std::string name, const std::vector<ValType> inputs,
|
||||
const std::vector<ValType> outputs, FunctionType f,
|
||||
void *user_data = NULL, std::function<void(void *)> free = nullptr)
|
||||
: name(name) {
|
||||
this->user_data.func = f;
|
||||
this->user_data.user_data = user_data;
|
||||
this->user_data.free_user_data = free;
|
||||
auto ptr = extism_function_new(
|
||||
this->name.c_str(), inputs.data(), inputs.size(), outputs.data(),
|
||||
outputs.size(), function_callback, &this->user_data, free_user_data);
|
||||
this->func = std::shared_ptr<ExtismFunction>(ptr, extism_function_free);
|
||||
}
|
||||
|
||||
void setNamespace(std::string s) {
|
||||
extism_function_set_namespace(this->func.get(), s.c_str());
|
||||
}
|
||||
|
||||
Function(const Function &f) { this->func = f.func; }
|
||||
|
||||
ExtismFunction *get() { return this->func.get(); }
|
||||
};
|
||||
|
||||
class CancelHandle {
|
||||
const ExtismCancelHandle *handle;
|
||||
|
||||
public:
|
||||
CancelHandle(const ExtismCancelHandle *x) : handle(x){};
|
||||
bool cancel() { return extism_plugin_cancel(this->handle); }
|
||||
};
|
||||
|
||||
class Plugin {
|
||||
std::vector<Function> functions;
|
||||
std::shared_ptr<ExtismContext> context;
|
||||
ExtismPlugin plugin;
|
||||
|
||||
public:
|
||||
ExtismPlugin *plugin;
|
||||
// Create a new plugin
|
||||
Plugin(const uint8_t *wasm, ExtismSize length, bool with_wasi = false,
|
||||
std::vector<Function> functions = std::vector<Function>())
|
||||
: functions(functions) {
|
||||
std::vector<const ExtismFunction *> ptrs;
|
||||
for (auto i : this->functions) {
|
||||
ptrs.push_back(i.get());
|
||||
}
|
||||
|
||||
char *errmsg = nullptr;
|
||||
this->plugin = extism_plugin_new(wasm, length, ptrs.data(), ptrs.size(),
|
||||
with_wasi, &errmsg);
|
||||
if (this->plugin == nullptr) {
|
||||
std::string s(errmsg);
|
||||
extism_plugin_new_error_free(errmsg);
|
||||
throw Error(s);
|
||||
Plugin(std::shared_ptr<ExtismContext> ctx, const uint8_t *wasm,
|
||||
ExtismSize length, bool with_wasi = false) {
|
||||
this->plugin = extism_plugin_new(ctx.get(), wasm, length, with_wasi);
|
||||
if (this->plugin < 0) {
|
||||
const char *err = extism_error(ctx.get(), -1);
|
||||
throw Error(err == nullptr ? "Unable to load plugin" : err);
|
||||
}
|
||||
this->context = ctx;
|
||||
}
|
||||
|
||||
Plugin(const std::string &str, bool with_wasi = false,
|
||||
std::vector<Function> functions = {})
|
||||
: Plugin((const uint8_t *)str.c_str(), str.size(), with_wasi, functions) {
|
||||
}
|
||||
|
||||
Plugin(const std::vector<uint8_t> &data, bool with_wasi = false,
|
||||
std::vector<Function> functions = {})
|
||||
: Plugin(data.data(), data.size(), with_wasi, functions) {}
|
||||
|
||||
CancelHandle cancelHandle() {
|
||||
return CancelHandle(extism_plugin_cancel_handle(this->plugin));
|
||||
}
|
||||
|
||||
#ifndef EXTISM_NO_JSON
|
||||
// Create a new plugin from Manifest
|
||||
Plugin(const Manifest &manifest, bool with_wasi = false,
|
||||
std::vector<Function> functions = {})
|
||||
: Plugin(manifest.json().c_str(), with_wasi, functions) {}
|
||||
|
||||
~Plugin() {
|
||||
extism_plugin_free(this->plugin);
|
||||
this->plugin = nullptr;
|
||||
extism_plugin_free(this->context.get(), this->plugin);
|
||||
this->plugin = -1;
|
||||
}
|
||||
|
||||
void config(const Config &data) {
|
||||
Json::Value conf;
|
||||
|
||||
for (auto k : data) {
|
||||
conf[k.first] = k.second;
|
||||
}
|
||||
|
||||
Json::FastWriter writer;
|
||||
auto s = writer.write(conf);
|
||||
this->config(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
void config(const char *json, size_t length) {
|
||||
bool b = extism_plugin_config(this->plugin, (const uint8_t *)json, length);
|
||||
void update(const uint8_t *wasm, size_t length, bool with_wasi = false) {
|
||||
bool b = extism_plugin_update(this->context.get(), this->plugin, wasm,
|
||||
length, with_wasi);
|
||||
if (!b) {
|
||||
const char *err = extism_plugin_error(this->plugin);
|
||||
throw Error(err == nullptr ? "Unable to update plugin config" : err);
|
||||
const char *err = extism_error(this->context.get(), -1);
|
||||
throw Error(err == nullptr ? "Unable to update plugin" : err);
|
||||
}
|
||||
}
|
||||
|
||||
void config(const std::string &json) {
|
||||
this->config(json.c_str(), json.size());
|
||||
}
|
||||
|
||||
// Call a plugin
|
||||
Buffer call(const std::string &func, const uint8_t *input,
|
||||
ExtismSize input_length) const {
|
||||
int32_t rc =
|
||||
extism_plugin_call(this->plugin, func.c_str(), input, input_length);
|
||||
ExtismSize input_length) {
|
||||
|
||||
int32_t rc = extism_plugin_call(this->context.get(), this->plugin,
|
||||
func.c_str(), input, input_length);
|
||||
if (rc != 0) {
|
||||
const char *error = extism_plugin_error(this->plugin);
|
||||
const char *error = extism_error(this->context.get(), this->plugin);
|
||||
if (error == nullptr) {
|
||||
throw Error("extism_call failed");
|
||||
}
|
||||
@@ -425,34 +73,42 @@ public:
|
||||
throw Error(error);
|
||||
}
|
||||
|
||||
ExtismSize length = extism_plugin_output_length(this->plugin);
|
||||
const uint8_t *ptr = extism_plugin_output_data(this->plugin);
|
||||
ExtismSize length =
|
||||
extism_plugin_output_length(this->context.get(), this->plugin);
|
||||
const uint8_t *ptr =
|
||||
extism_plugin_output_data(this->context.get(), this->plugin);
|
||||
return Buffer(ptr, length);
|
||||
}
|
||||
|
||||
// Call a plugin function with std::vector<uint8_t> input
|
||||
Buffer call(const std::string &func,
|
||||
const std::vector<uint8_t> &input) const {
|
||||
Buffer call(const std::string &func, const std::vector<uint8_t> &input) {
|
||||
return this->call(func, input.data(), input.size());
|
||||
}
|
||||
|
||||
// Call a plugin function with string input
|
||||
Buffer call(const std::string &func,
|
||||
const std::string &input = std::string()) const {
|
||||
Buffer call(const std::string &func, const std::string &input) {
|
||||
return this->call(func, (const uint8_t *)input.c_str(), input.size());
|
||||
}
|
||||
|
||||
// Returns true if the specified function exists
|
||||
bool functionExists(const std::string &func) const {
|
||||
return extism_plugin_function_exists(this->plugin, func.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
// Set global log file for plugins
|
||||
inline bool setLogFile(const char *filename, const char *level) {
|
||||
return extism_log_file(filename, level);
|
||||
}
|
||||
class Context {
|
||||
public:
|
||||
std::shared_ptr<ExtismContext> pointer;
|
||||
Context() {
|
||||
this->pointer = std::shared_ptr<ExtismContext>(extism_context_new(),
|
||||
extism_context_free);
|
||||
}
|
||||
|
||||
Plugin plugin(const uint8_t *wasm, size_t length, bool with_wasi = false) {
|
||||
return Plugin(this->pointer, wasm, length, with_wasi);
|
||||
}
|
||||
|
||||
Plugin plugin(const std::string &str, bool with_wasi = false) {
|
||||
return Plugin(this->pointer, (const uint8_t *)str.c_str(), str.size(),
|
||||
with_wasi);
|
||||
}
|
||||
|
||||
Plugin plugin(const std::vector<uint8_t> &data, bool with_wasi = false) {
|
||||
return Plugin(this->pointer, data.data(), data.size(), with_wasi);
|
||||
}
|
||||
};
|
||||
|
||||
// Get libextism version
|
||||
inline std::string version() { return std::string(extism_version()); }
|
||||
} // namespace extism
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
#include "../extism.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
std::vector<uint8_t> read(const char *filename) {
|
||||
std::ifstream file(filename, std::ios::binary);
|
||||
return std::vector<uint8_t>((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
||||
const std::string code = "../../wasm/code.wasm";
|
||||
|
||||
namespace {
|
||||
using namespace extism;
|
||||
|
||||
TEST(Plugin, Manifest) {
|
||||
Manifest manifest = Manifest::path(code);
|
||||
manifest.set_config("a", "1");
|
||||
|
||||
Plugin plugin(manifest);
|
||||
|
||||
Buffer buf = plugin.call("count_vowels", "this is a test");
|
||||
ASSERT_EQ((std::string)buf, "{\"count\": 4}");
|
||||
}
|
||||
|
||||
TEST(Plugin, BadManifest) {
|
||||
Manifest manifest;
|
||||
ASSERT_THROW(Plugin plugin(manifest), Error);
|
||||
}
|
||||
|
||||
TEST(Plugin, Bytes) {
|
||||
auto wasm = read(code.c_str());
|
||||
ASSERT_NO_THROW(Plugin plugin(wasm));
|
||||
Plugin plugin(wasm);
|
||||
|
||||
Buffer buf = plugin.call("count_vowels", "this is another test");
|
||||
ASSERT_EQ(buf.string(), "{\"count\": 6}");
|
||||
}
|
||||
|
||||
TEST(Plugin, UpdateConfig) {
|
||||
auto wasm = read(code.c_str());
|
||||
Plugin plugin(wasm);
|
||||
|
||||
Config config;
|
||||
config["abc"] = "123";
|
||||
ASSERT_NO_THROW(plugin.config(config));
|
||||
}
|
||||
|
||||
TEST(Plugin, FunctionExists) {
|
||||
auto wasm = read(code.c_str());
|
||||
Plugin plugin(wasm);
|
||||
|
||||
ASSERT_FALSE(plugin.functionExists("bad_function"));
|
||||
ASSERT_TRUE(plugin.functionExists("count_vowels"));
|
||||
}
|
||||
|
||||
TEST(Plugin, HostFunction) {
|
||||
auto wasm = read("../../wasm/code-functions.wasm");
|
||||
auto t = std::vector<ValType>{ValType::I64};
|
||||
Function hello_world =
|
||||
Function("hello_world", t, t,
|
||||
[](CurrentPlugin plugin, const std::vector<Val> ¶ms,
|
||||
std::vector<Val> &results, void *user_data) {
|
||||
auto offs = plugin.alloc(4);
|
||||
memcpy(plugin.memory() + offs, "test", 4);
|
||||
results[0].v.i64 = (int64_t)offs;
|
||||
});
|
||||
auto functions = std::vector<Function>{
|
||||
hello_world,
|
||||
};
|
||||
Plugin plugin(wasm, true, functions);
|
||||
auto buf = plugin.call("count_vowels", "aaa");
|
||||
ASSERT_EQ(buf.length, 4);
|
||||
ASSERT_EQ((std::string)buf, "test");
|
||||
}
|
||||
|
||||
void callThread(Plugin *plugin) {
|
||||
auto buf = plugin->call("count_vowels", "aaa").string();
|
||||
ASSERT_EQ(buf.size(), 10);
|
||||
ASSERT_EQ(buf, "testing123");
|
||||
}
|
||||
|
||||
TEST(Plugin, MultipleThreads) {
|
||||
auto wasm = read("../../wasm/code-functions.wasm");
|
||||
auto t = std::vector<ValType>{ValType::I64};
|
||||
Function hello_world =
|
||||
Function("hello_world", t, t,
|
||||
[](CurrentPlugin plugin, const std::vector<Val> ¶ms,
|
||||
std::vector<Val> &results, void *user_data) {
|
||||
auto offs = plugin.alloc(10);
|
||||
memcpy(plugin.memory() + offs, "testing123", 10);
|
||||
results[0].v.i64 = (int64_t)offs;
|
||||
});
|
||||
auto functions = std::vector<Function>{
|
||||
hello_world,
|
||||
};
|
||||
Plugin plugin(wasm, true, functions);
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
threads.push_back(std::thread(callThread, &plugin));
|
||||
}
|
||||
|
||||
for (auto &th : threads) {
|
||||
th.join();
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
7
d/.gitignore
vendored
7
d/.gitignore
vendored
@@ -1,7 +0,0 @@
|
||||
# Generated by host system's C preprocessor
|
||||
# See https://dlang.org/spec/importc.html#manual-cpp
|
||||
runtime.i
|
||||
|
||||
docs.json
|
||||
extism-test-*
|
||||
*.lst
|
||||
@@ -1,4 +0,0 @@
|
||||
# D Host SDK
|
||||
|
||||
Development of this library has moved to [this repo](https://github.com/extism/d-sdk#readme).
|
||||
|
||||
17
d/examples/hello/.gitignore
vendored
17
d/examples/hello/.gitignore
vendored
@@ -1,17 +0,0 @@
|
||||
.dub
|
||||
docs.json
|
||||
__dummy.html
|
||||
docs/
|
||||
/extism_hello
|
||||
/hello
|
||||
hello.so
|
||||
hello.dylib
|
||||
hello.dll
|
||||
hello.a
|
||||
hello.lib
|
||||
hello-test-*
|
||||
*.exe
|
||||
*.pdb
|
||||
*.o
|
||||
*.obj
|
||||
*.lst
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"name": "hello",
|
||||
"description": "A minimal Extism usage example",
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
"Chance Snow <git@chancesnow.me>",
|
||||
"Extism contributors"
|
||||
],
|
||||
"copyright": "Copyright © 2023, Extism contributors",
|
||||
"dependencies": {
|
||||
"extism": {
|
||||
"path": "../../../"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import std.conv: castFrom, to;
|
||||
import std.file;
|
||||
import std.functional: toDelegate;
|
||||
import std.stdio;
|
||||
import std.string: representation;
|
||||
import std.typecons : Yes;
|
||||
|
||||
import extism;
|
||||
|
||||
void main() {
|
||||
auto wasm = cast(ubyte[]) read("wasm/code-functions.wasm");
|
||||
// FIXME: Creating the plugin results in EXC_BAD_ACCESS (segfault?) from `extism_plugin_new`
|
||||
auto plugin = new Plugin(wasm, [
|
||||
Function!string(
|
||||
"hello_world", /* Inputs */ [ValType.i64], /* Outputs */ [ValType.i64], toDelegate(&helloWorld), "Hello, again!"
|
||||
),
|
||||
], Yes.withWasi);
|
||||
|
||||
auto input = "aeiou";
|
||||
plugin.call("count_vowels", cast(ubyte[]) input.representation);
|
||||
writeln(plugin.outputData);
|
||||
}
|
||||
|
||||
///
|
||||
void helloWorld(CurrentPlugin plugin, const Val[] inputs, Val[] outputs, void *data) {
|
||||
writeln("Hello from D!");
|
||||
writeln(data);
|
||||
|
||||
ExtismSize ptr_offs = inputs[0].v.i64;
|
||||
auto buf = plugin.memory(ptr_offs);
|
||||
writeln(buf);
|
||||
outputs[0].v.i64 = inputs[0].v.i64;
|
||||
}
|
||||
258
d/extism.d
258
d/extism.d
@@ -1,258 +0,0 @@
|
||||
module extism;
|
||||
|
||||
import std.conv: castFrom, to;
|
||||
import std.meta: Alias;
|
||||
import std.string: fromStringz, toStringz;
|
||||
|
||||
import runtime;
|
||||
|
||||
/// A list of all possible value types in WebAssembly.
|
||||
enum ValType {
|
||||
i32 = I32,
|
||||
i64 = I64,
|
||||
f32 = F32,
|
||||
f64 = F64,
|
||||
v128 = V128,
|
||||
funcRef = FuncRef,
|
||||
externRef = ExternRef,
|
||||
}
|
||||
|
||||
// Opaque Pointers
|
||||
///
|
||||
alias CancelHandle = Alias!(void*);
|
||||
///
|
||||
alias CurrentPlugin = Alias!(void*);
|
||||
|
||||
///
|
||||
alias ExtismSize = ulong;
|
||||
|
||||
/// A union type for host function argument/return values.
|
||||
union ValUnion {
|
||||
///
|
||||
int i32;
|
||||
///
|
||||
long i64;
|
||||
///
|
||||
float f32;
|
||||
///
|
||||
double f64;
|
||||
}
|
||||
|
||||
/// Holds the type and value of a function argument/return.
|
||||
struct Val {
|
||||
///
|
||||
ValType t;
|
||||
///
|
||||
ValUnion v;
|
||||
}
|
||||
|
||||
/// Host function signature.
|
||||
///
|
||||
/// Used to register host functions with plugins.
|
||||
/// Params:
|
||||
/// plugin: the currently executing plugin from within a host function
|
||||
/// inputs: argument values
|
||||
/// outputs: return values
|
||||
/// data: user data associated with the host function
|
||||
alias FunctionType = void delegate(
|
||||
CurrentPlugin plugin, const Val[] inputs, Val[] outputs, void* data
|
||||
);
|
||||
|
||||
/// Returns: A slice of an allocated memory block of the currently running plugin.
|
||||
ubyte[] memory(CurrentPlugin plugin, ulong n) {
|
||||
auto length = extism_current_plugin_memory_length(cast(ExtismCurrentPlugin*) plugin, n);
|
||||
return extism_current_plugin_memory(cast(ExtismCurrentPlugin*) plugin)[n .. (n + length)];
|
||||
}
|
||||
|
||||
/// Allocate a memory block in the currently running plugin.
|
||||
ulong memoryAlloc(CurrentPlugin plugin, ulong n) {
|
||||
return extism_current_plugin_memory_alloc(cast(ExtismCurrentPlugin*) plugin, n);
|
||||
}
|
||||
|
||||
/// Free an allocated memory block.
|
||||
void memoryFree(CurrentPlugin plugin, ulong ptr) {
|
||||
extism_current_plugin_memory_free(cast(ExtismCurrentPlugin*) plugin, ptr);
|
||||
}
|
||||
|
||||
/// A host function, where `T` is the type of its user data.
|
||||
struct Function(T) {
|
||||
/// Managed pointer.
|
||||
ExtismFunction* func;
|
||||
alias func this;
|
||||
private string _namespace = null;
|
||||
|
||||
/// Create a new host function.
|
||||
/// Params:
|
||||
/// name: function name, this should be valid UTF-8
|
||||
/// inputs: argument types
|
||||
/// outputs: return types
|
||||
/// func: the function to call
|
||||
/// userData: a pointer that will be passed to the function when it's called. This value should live as long as the function exists.
|
||||
/// freeUserData: a callback to release the `userData`` value when the resulting `Function` is freed.
|
||||
this(
|
||||
string name, const ValType[] inputs, const ValType[] outputs, FunctionType func,
|
||||
T userData, void function(T userData) freeUserData = null
|
||||
) {
|
||||
import std.functional: toDelegate;
|
||||
|
||||
// Bind the given host function with C linkage
|
||||
auto funcClosure = ((
|
||||
ExtismCurrentPlugin* plugin,
|
||||
const ExtismVal* inputs, ulong numInputs, ExtismVal* outputs, ulong numOutputs,
|
||||
void* data
|
||||
) {
|
||||
func(plugin, (cast(const Val*) inputs)[0 .. numInputs], (cast(Val*) outputs)[0 .. numOutputs], data);
|
||||
}).toDelegate.bindDelegate;
|
||||
|
||||
// Bind the `freeUserData` function with C linkage
|
||||
auto freeUserDataHandler = freeUserData is null ? null : ((void* userDataPtr) {
|
||||
if (userDataPtr is null) return;
|
||||
freeUserData((&userDataPtr).to!T);
|
||||
}).toDelegate.bindDelegate;
|
||||
|
||||
this.func = extism_function_new(
|
||||
name.toStringz,// See https://dlang.org/spec/importc.html#enums
|
||||
// See https://forum.dlang.org/post/qmidcpaxctbuphcyvkdc@forum.dlang.org
|
||||
castFrom!(const(ValType)*)
|
||||
.to!(typeof(ExtismVal.t)*)(inputs.ptr), inputs.length,
|
||||
castFrom!(const(ValType)*).to!(typeof(ExtismVal.t)*)(outputs.ptr), outputs.length,
|
||||
funcClosure,
|
||||
&userData,
|
||||
freeUserDataHandler,
|
||||
);
|
||||
}
|
||||
|
||||
~this() {
|
||||
extism_function_free(func);
|
||||
}
|
||||
|
||||
/// Get the namespace of this function.
|
||||
string namespace() {
|
||||
return this._namespace;
|
||||
}
|
||||
/// Set the namespace of this function.
|
||||
void namespace(string value) {
|
||||
this._namespace = value;
|
||||
extism_function_set_namespace(func, value.toStringz);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
struct Plugin {
|
||||
import std.uuid: UUID;
|
||||
|
||||
/// Managed pointer.
|
||||
ExtismPlugin* plugin;
|
||||
alias plugin this;
|
||||
|
||||
/// Create a new plugin.
|
||||
/// Params:
|
||||
/// wasm: is a WASM module (wat or wasm) or a JSON encoded manifest
|
||||
/// functions: is an array of ExtismFunction*
|
||||
/// withWasi: enables/disables WASI
|
||||
/// Throws: `Exception` if the plugin could not be created.
|
||||
this(const ubyte[] wasm, const(ExtismFunction)*[] functions, bool withWasi = false) {
|
||||
char* errorMsgPtr = null;
|
||||
plugin = extism_plugin_new(
|
||||
wasm.ptr, wasm.length, cast(ExtismFunction**) functions.ptr, functions.length, withWasi, &errorMsgPtr
|
||||
);
|
||||
// See https://github.com/extism/extism/blob/ddcbeec3debe787293a9957c8be88f80a64b7c22/c/main.c#L67
|
||||
// Instead of terminating the host process, throw.
|
||||
if (plugin !is null)
|
||||
return;
|
||||
auto errorMsg = errorMsgPtr.fromStringz.idup;
|
||||
extism_plugin_new_error_free(errorMsgPtr);
|
||||
// TODO: Subclass `Exception` for better error handling
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
|
||||
~this() {
|
||||
extism_plugin_free(plugin);
|
||||
}
|
||||
|
||||
/// Get a plugin's ID.
|
||||
UUID id() {
|
||||
return UUID(extism_plugin_id(plugin)[0 .. 16]);
|
||||
}
|
||||
|
||||
/// Get the error associated with this `Plugin`.
|
||||
string error() {
|
||||
return extism_error(plugin).fromStringz.idup;
|
||||
}
|
||||
|
||||
/// Update plugin config values, this will merge with the existing values.
|
||||
bool config(ubyte[] json) {
|
||||
return extism_plugin_config(plugin, json.ptr, json.length);
|
||||
}
|
||||
|
||||
/// See_Also: `cancel`
|
||||
const(CancelHandle) cancelHandle() {
|
||||
return extism_plugin_cancel_handle(plugin);
|
||||
}
|
||||
|
||||
/// Cancel a running plugin.
|
||||
/// See_Also: `cancelHandle`
|
||||
bool cancel(const CancelHandle handle) {
|
||||
return extism_plugin_cancel(cast(ExtismCancelHandle*) handle);
|
||||
}
|
||||
|
||||
/// Returns: Whether a function with `name` exists.
|
||||
bool functionExists(string name) {
|
||||
return extism_plugin_function_exists(plugin, name.toStringz);
|
||||
}
|
||||
|
||||
/// Call a function.
|
||||
/// Params:
|
||||
/// funcName: is the function to call
|
||||
/// data: is the input data
|
||||
void call(string funcName, ubyte[] data = null) {
|
||||
// Returns `0` if the call was successful, otherwise `-1`.
|
||||
if (extism_plugin_call(plugin, funcName.toStringz, data.ptr, data.length) != 0)
|
||||
throw new Exception(this.error);
|
||||
}
|
||||
|
||||
/// Get the plugin's output data.
|
||||
///
|
||||
/// Note: This copies the data into a managed buffer.
|
||||
/// Remarks: Use `outputData.length` to retrieve size of plugin output.
|
||||
ubyte[] outputData() {
|
||||
import std.algorithm: copy;
|
||||
|
||||
auto outputLength = extism_plugin_output_length(plugin);
|
||||
auto outputData = extism_plugin_output_data(plugin)[0 .. outputLength];
|
||||
auto buffer = new ubyte[outputLength];
|
||||
assert(
|
||||
outputData.copy(buffer).length == 0,
|
||||
"Output data was not completely copied into buffer, i.e. buffer was not filled."
|
||||
);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the error associated with a `Context` or `Plugin`, if plugin is -1 then the context error will be returned.
|
||||
|
||||
/// Set log file and level.
|
||||
bool setLogFile(string filename, string logLevel) {
|
||||
return extism_log_file(filename.toStringz, logLevel.toStringz);
|
||||
}
|
||||
|
||||
/// Get the Extism version string.
|
||||
string version_() {
|
||||
return extism_version().fromStringz.idup;
|
||||
}
|
||||
|
||||
import std.traits: isDelegate;
|
||||
|
||||
/// Transform the given delegate into a static function pointer with C linkage.
|
||||
/// See_Also: <a href="https://stackoverflow.com/a/22845722/1363247">stackoverflow.com/a/22845722/1363247</a>
|
||||
package auto bindDelegate(Func)(Func f) if (isDelegate!Func) {
|
||||
import std.traits: ParameterTypeTuple, ReturnType;
|
||||
|
||||
static Func delegate_;
|
||||
delegate_ = f;
|
||||
extern (C) static ReturnType!Func func(ParameterTypeTuple!Func args) {
|
||||
return delegate_(args);
|
||||
}
|
||||
|
||||
return &func;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
#include "runtime/extism.h"
|
||||
479
dotnet/.gitignore
vendored
479
dotnet/.gitignore
vendored
@@ -1,479 +0,0 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# Tye
|
||||
.tye/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||
*.vbp
|
||||
|
||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||
*.dsw
|
||||
*.dsp
|
||||
|
||||
# Visual Studio 6 technical files
|
||||
*.ncb
|
||||
*.aps
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
|
||||
##
|
||||
## Visual studio for Mac
|
||||
##
|
||||
|
||||
|
||||
# globs
|
||||
Makefile.in
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
config.make
|
||||
config.status
|
||||
aclocal.m4
|
||||
install-sh
|
||||
autom4te.cache/
|
||||
*.tar.gz
|
||||
tarballs/
|
||||
test-results/
|
||||
|
||||
# Mac bundle stuff
|
||||
*.dmg
|
||||
*.app
|
||||
|
||||
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
nuget/runtimes/win-x64.dll
|
||||
@@ -1,37 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33110.190
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.Sdk", "src\Extism.Sdk\Extism.Sdk.csproj", "{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.Sdk.Tests", "test\Extism.Sdk\Extism.Sdk.Tests.csproj", "{DB440D61-C781-4C59-9223-9A79CC9FB4E7}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extism.Sdk.Sample", "samples\Extism.Sdk.Sample\Extism.Sdk.Sample.csproj", "{2232E572-E8BA-46A1-AF31-E4168960DB75}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1FAA7B6E-249C-4E4C-AE7A-A493A9D24475}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DB440D61-C781-4C59-9223-9A79CC9FB4E7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2232E572-E8BA-46A1-AF31-E4168960DB75}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {2B6BF267-F2A5-4CB5-8DFD-F11CC8787E6B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,4 +0,0 @@
|
||||
# Dotnet Host SDK
|
||||
|
||||
This contains the `0.x` version of the SDK. Development of this library has moved to [this repo](https://github.com/extism/dotnet-sdk#readme).
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Authors>Extism Contributors</Authors>
|
||||
<PackageTags>extism, wasm, plugin</PackageTags>
|
||||
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageProjectUrl>https://extism.org</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/your/repository.git</RepositoryUrl>
|
||||
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<Deterministic>true</Deterministic>
|
||||
<NoBuild>true</NoBuild>
|
||||
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||
|
||||
<MinVerIgnoreHeight>true</MinVerIgnoreHeight>
|
||||
<MinVerTagPrefix>v</MinVerTagPrefix>
|
||||
<MinVerVerbosity>normal</MinVerVerbosity>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MinVer" Version="4.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,14 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<NuspecFile>Extism.runtime.all.nuspec</NuspecFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="Replace" BeforeTargets="GenerateNuspec">
|
||||
<WriteLinesToFile
|
||||
File="$(NuspecFile)"
|
||||
Lines="$([System.IO.File]::ReadAllText($(NuspecFile)).Replace('$Version','$(MinVerVersion)'))"
|
||||
Overwrite="true"/>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<package>
|
||||
<metadata>
|
||||
<id>Extism.runtime.all</id>
|
||||
<version>$Version</version>
|
||||
<authors>Extism Contributors</authors>
|
||||
<owners>Extism Contributors</owners>
|
||||
<description>Internal implementation package for Extism</description>
|
||||
<tags>extism wasm plugin</tags>
|
||||
<license type="expression">BSD-3-Clause</license>
|
||||
<projectUrl>https://github.com/extism/extism</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<copyright>Copyright © 2023 Extism Contributors</copyright>
|
||||
<readme>README.md</readme>
|
||||
<dependencies>
|
||||
<dependency id="Extism.runtime.linux-arm64" version="$Version" />
|
||||
<dependency id="Extism.runtime.linux-musl-arm64" version="$Version" />
|
||||
<dependency id="Extism.runtime.linux-x64" version="$Version" />
|
||||
<dependency id="Extism.runtime.osx-arm64" version="$Version" />
|
||||
<dependency id="Extism.runtime.osx-x64" version="$Version" />
|
||||
<dependency id="Extism.runtime.win-x64" version="$Version" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="README.md" target="" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -1,15 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>Extism.runtime.linux-arm64</PackageId>
|
||||
<Description>Internal implementation package for Extism to work on Linux ARM64</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\linux-arm64\native\libextism.so"
|
||||
CopyToOutputDirectory="Always"
|
||||
Pack="true"
|
||||
PackagePath="runtimes\linux-arm64\native\libextism.so" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,15 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>Extism.runtime.linux-musl-arm64</PackageId>
|
||||
<Description>Internal implementation package for Extism to work on Linux Musl ARM64</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\linux-musl-arm64\native\libextism.so"
|
||||
CopyToOutputDirectory="Always"
|
||||
Pack="true"
|
||||
PackagePath="runtimes\linux-musl-arm64\native\libextism.so" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,15 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>Extism.runtime.linux-x64</PackageId>
|
||||
<Description>Internal implementation package for Extism to work on Linux x64</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\linux-x64\native\libextism.so"
|
||||
CopyToOutputDirectory="Always"
|
||||
Pack="true"
|
||||
PackagePath="runtimes\linux-x64\native\libextism.so" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,15 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>Extism.runtime.osx-arm64</PackageId>
|
||||
<Description>Internal implementation package for Extism to work on macOS ARM64</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\osx-arm64\native\libextism.dylib"
|
||||
CopyToOutputDirectory="Always"
|
||||
Pack="true"
|
||||
PackagePath="runtimes\osx-arm64\native\libextism.dylib" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,15 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>Extism.runtime.osx-x64</PackageId>
|
||||
<Description>Internal implementation package for Extism to work on macOS x64</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\osx-x64\native\libextism.dylib"
|
||||
CopyToOutputDirectory="Always"
|
||||
Pack="true"
|
||||
PackagePath="runtimes\osx-x64\native\libextism.dylib" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,15 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>Extism.runtime.win-x64</PackageId>
|
||||
<Description>Internal implementation package for Extism to work on Windows x64</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes\win-x64\native\extism.dll"
|
||||
CopyToOutputDirectory="Always"
|
||||
Pack="true"
|
||||
PackagePath="runtimes\win-x64\native\extism.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,2 +0,0 @@
|
||||
# Extism
|
||||
The cross-language framework for building with WebAssembly (wasm).
|
||||
@@ -1 +0,0 @@
|
||||
win-x64.dll
|
||||
@@ -1,29 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\..\..\wasm\code.wasm" Link="code.wasm">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="..\..\..\wasm\code-functions.wasm" Link="code-functions.wasm">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Extism.runtime.win-x64" Version="0.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Extism.Sdk\Extism.Sdk.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
@@ -1,38 +0,0 @@
|
||||
using Extism.Sdk;
|
||||
using Extism.Sdk.Native;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
var userData = Marshal.StringToHGlobalAnsi("Hello again!");
|
||||
|
||||
using var helloWorld = new HostFunction(
|
||||
"hello_world",
|
||||
"env",
|
||||
new[] { ExtismValType.I64 },
|
||||
new[] { ExtismValType.I64 },
|
||||
userData,
|
||||
HelloWorld);
|
||||
|
||||
void HelloWorld(CurrentPlugin plugin, Span<ExtismVal> inputs, Span<ExtismVal> outputs, nint data)
|
||||
{
|
||||
Console.WriteLine("Hello from .NET!");
|
||||
|
||||
var text = Marshal.PtrToStringAnsi(data);
|
||||
Console.WriteLine(text);
|
||||
|
||||
var input = plugin.ReadString(new nint(inputs[0].v.i64));
|
||||
Console.WriteLine($"Input: {input}");
|
||||
|
||||
outputs[0].v.i64 = plugin.WriteString(input);
|
||||
}
|
||||
|
||||
var wasm = File.ReadAllBytes("./code-functions.wasm");
|
||||
using var plugin = new Plugin(wasm, new[] { helloWorld }, withWasi: true);
|
||||
|
||||
var output = Encoding.UTF8.GetString(
|
||||
plugin.CallFunction("count_vowels", Encoding.UTF8.GetBytes("Hello World!"))
|
||||
);
|
||||
|
||||
Console.WriteLine($"Output: {output}");
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
## Example 1
|
||||
|
||||
This example shows how you can use the library in the most basic way.
|
||||
It loads up the sample wasm plugin and lets you to pass inputs to it and show the ouput.
|
||||
**Please note that on Windows you have to manually copy the `extism.dll` file to the ouput directory.**
|
||||
@@ -1,24 +0,0 @@
|
||||
<!-- Recommended practices for publishing nuget packages from: https://devblogs.microsoft.com/dotnet/producing-packages-with-source-link/ -->
|
||||
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<!-- Publish the repository URL in the built .nupkg (in the NuSpec <Repository> element) -->
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
|
||||
<!-- Embed source files that are not tracked by the source control manager in the PDB -->
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
|
||||
<!-- Recommended: Embed symbols containing Source Link in the main file (exe/dll) -->
|
||||
<DebugType>embedded</DebugType>
|
||||
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,138 +0,0 @@
|
||||
using Extism.Sdk.Native;
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace Extism.Sdk
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the current plugin. Can only be used within <see cref="HostFunction"/>s.
|
||||
/// </summary>
|
||||
public class CurrentPlugin
|
||||
{
|
||||
internal CurrentPlugin(nint nativeHandle)
|
||||
{
|
||||
NativeHandle = nativeHandle;
|
||||
}
|
||||
|
||||
internal nint NativeHandle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pointer to the memory of the currently running plugin.
|
||||
/// NOTE: this should only be called from host functions.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public nint GetMemory()
|
||||
{
|
||||
return LibExtism.extism_current_plugin_memory(NativeHandle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a string from a memory block using UTF8.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <returns></returns>
|
||||
public string ReadString(nint pointer)
|
||||
{
|
||||
return ReadString(pointer, Encoding.UTF8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a string form a memory block.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <param name="encoding"></param>
|
||||
/// <returns></returns>
|
||||
public string ReadString(nint pointer, Encoding encoding)
|
||||
{
|
||||
var buffer = ReadBytes(pointer);
|
||||
|
||||
return encoding.GetString(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a span of bytes for a given block.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <returns></returns>
|
||||
public unsafe Span<byte> ReadBytes(nint pointer)
|
||||
{
|
||||
var mem = GetMemory();
|
||||
var length = (int)BlockLength(pointer);
|
||||
var ptr = (byte*)mem + pointer;
|
||||
|
||||
return new Span<byte>(ptr, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string into the current plugin memory using UTF-8 encoding and returns the pointer of the block.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public nint WriteString(string value)
|
||||
=> WriteString(value, Encoding.UTF8);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a string into the current plugin memory and returns the pointer of the block.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="encoding"></param>
|
||||
public nint WriteString(string value, Encoding encoding)
|
||||
{
|
||||
var bytes = encoding.GetBytes(value);
|
||||
var pointer = AllocateBlock(bytes.Length);
|
||||
WriteBytes(pointer, bytes);
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte array into a block of memory.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <param name="bytes"></param>
|
||||
public unsafe void WriteBytes(nint pointer, Span<byte> bytes)
|
||||
{
|
||||
var length = BlockLength(pointer);
|
||||
if (length < bytes.Length)
|
||||
{
|
||||
throw new InvalidOperationException("Destination block length is less than source block length.");
|
||||
}
|
||||
|
||||
var mem = GetMemory();
|
||||
var ptr = (void*)(mem + pointer);
|
||||
var destination = new Span<byte>(ptr, bytes.Length);
|
||||
|
||||
bytes.CopyTo(destination);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Frees a block of memory belonging to the current plugin.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
public void FreeBlock(nint pointer)
|
||||
{
|
||||
LibExtism.extism_current_plugin_memory_free(NativeHandle, pointer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocate a memory block in the currently running plugin.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public nint AllocateBlock(long length)
|
||||
{
|
||||
return LibExtism.extism_current_plugin_memory_alloc(NativeHandle, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the length of an allocated block.
|
||||
/// NOTE: this should only be called from host functions.
|
||||
/// </summary>
|
||||
/// <param name="pointer"></param>
|
||||
/// <returns></returns>
|
||||
public long BlockLength(nint pointer)
|
||||
{
|
||||
return LibExtism.extism_current_plugin_memory_length(NativeHandle, pointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<LangVersion>10</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PackageId>Extism.Sdk</PackageId>
|
||||
<Version>0.7.0</Version>
|
||||
<Authors>Extism Contributors</Authors>
|
||||
<Description>Extism SDK that allows hosting Extism plugins in .NET apps.</Description>
|
||||
<Tags>extism, wasm, plugin</Tags>
|
||||
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="README.md" Pack="true" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,40 +0,0 @@
|
||||
namespace Extism.Sdk.Native;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents errors that occur during calling Extism functions.
|
||||
/// </summary>
|
||||
public class ExtismException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExtismException"/> class.
|
||||
/// </summary>
|
||||
public ExtismException()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExtismException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error .</param>
|
||||
public ExtismException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ExtismException"/> class
|
||||
/// with a specified error message and a reference to the inner exception
|
||||
/// that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
/// <param name="innerException">
|
||||
/// The exception that is the cause of the current exception, or a null reference
|
||||
/// (Nothing in Visual Basic) if no inner exception is specified.
|
||||
/// </param>
|
||||
public ExtismException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
using Extism.Sdk.Native;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Extism.Sdk
|
||||
{
|
||||
/// <summary>
|
||||
/// A host function signature.
|
||||
/// </summary>
|
||||
/// <param name="plugin">Plugin Index</param>
|
||||
/// <param name="inputs">Input parameters</param>
|
||||
/// <param name="outputs">Output parameters, the host function can change this.</param>
|
||||
/// <param name="userData">A data passed in during Host Function creation.</param>
|
||||
public delegate void ExtismFunction(CurrentPlugin plugin, Span<ExtismVal> inputs, Span<ExtismVal> outputs, IntPtr userData);
|
||||
|
||||
/// <summary>
|
||||
/// A function provided by the host that plugins can call.
|
||||
/// </summary>
|
||||
public class HostFunction : IDisposable
|
||||
{
|
||||
private const int DisposedMarker = 1;
|
||||
private int _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a Host Function.
|
||||
/// </summary>
|
||||
/// <param name="functionName">The literal name of the function, how it would be called from a <see cref="Plugin"/>.</param>
|
||||
/// <param name="inputTypes">The types of the input arguments/parameters the <see cref="Plugin"/> caller will provide.</param>
|
||||
/// <param name="outputTypes">The types of the output returned from the host function to the <see cref="Plugin"/>.</param>
|
||||
/// <param name="userData">An opaque pointer to an object from the host, accessible to the <see cref="Plugin"/>.
|
||||
/// NOTE: it is the shared responsibility of the host and <see cref="Plugin"/> to cast/dereference this value properly.</param>
|
||||
/// <param name="hostFunction"></param>
|
||||
public HostFunction(
|
||||
string functionName,
|
||||
Span<ExtismValType> inputTypes,
|
||||
Span<ExtismValType> outputTypes,
|
||||
IntPtr userData,
|
||||
ExtismFunction hostFunction) :
|
||||
this(functionName, "", inputTypes, outputTypes, userData, hostFunction)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a Host Function.
|
||||
/// </summary>
|
||||
/// <param name="functionName">The literal name of the function, how it would be called from a <see cref="Plugin"/>.</param>
|
||||
/// <param name="namespace">Function namespace.</param>
|
||||
/// <param name="inputTypes">The types of the input arguments/parameters the <see cref="Plugin"/> caller will provide.</param>
|
||||
/// <param name="outputTypes">The types of the output returned from the host function to the <see cref="Plugin"/>.</param>
|
||||
/// <param name="userData">An opaque pointer to an object from the host, accessible to the <see cref="Plugin"/>.
|
||||
/// NOTE: it is the shared responsibility of the host and <see cref="Plugin"/> to cast/dereference this value properly.</param>
|
||||
/// <param name="hostFunction"></param>
|
||||
unsafe public HostFunction(
|
||||
string functionName,
|
||||
string @namespace,
|
||||
Span<ExtismValType> inputTypes,
|
||||
Span<ExtismValType> outputTypes,
|
||||
IntPtr userData,
|
||||
ExtismFunction hostFunction)
|
||||
{
|
||||
fixed (ExtismValType* inputs = inputTypes)
|
||||
fixed (ExtismValType* outputs = outputTypes)
|
||||
{
|
||||
NativeHandle = LibExtism.extism_function_new(functionName, inputs, inputTypes.Length, outputs, outputTypes.Length, CallbackImpl, userData, IntPtr.Zero);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(@namespace))
|
||||
{
|
||||
LibExtism.extism_function_set_namespace(NativeHandle, @namespace);
|
||||
}
|
||||
|
||||
void CallbackImpl(
|
||||
nint plugin,
|
||||
ExtismVal* inputsPtr,
|
||||
uint n_inputs,
|
||||
ExtismVal* outputsPtr,
|
||||
uint n_outputs,
|
||||
IntPtr data)
|
||||
{
|
||||
var outputs = new Span<ExtismVal>(outputsPtr, (int)n_outputs);
|
||||
var inputs = new Span<ExtismVal>(inputsPtr, (int)n_inputs);
|
||||
|
||||
hostFunction(new CurrentPlugin(plugin), inputs, outputs, data);
|
||||
}
|
||||
}
|
||||
|
||||
internal IntPtr NativeHandle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Frees all resources held by this Host Function.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _disposed, DisposedMarker) == DisposedMarker)
|
||||
{
|
||||
// Already disposed.
|
||||
return;
|
||||
}
|
||||
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throw an appropriate exception if the Host Function has been disposed.
|
||||
/// </summary>
|
||||
/// <exception cref="ObjectDisposedException"></exception>
|
||||
protected void CheckNotDisposed()
|
||||
{
|
||||
Interlocked.MemoryBarrier();
|
||||
if (_disposed == DisposedMarker)
|
||||
{
|
||||
ThrowDisposedException();
|
||||
}
|
||||
}
|
||||
|
||||
[DoesNotReturn]
|
||||
private static void ThrowDisposedException()
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(HostFunction));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Frees all resources held by this Host Function.
|
||||
/// </summary>
|
||||
unsafe protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Free up any managed resources here
|
||||
}
|
||||
|
||||
// Free up unmanaged resources
|
||||
LibExtism.extism_function_free(NativeHandle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destructs the current Host Function and frees all resources used by it.
|
||||
/// </summary>
|
||||
~HostFunction()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Extism.Sdk.Native;
|
||||
|
||||
/// <summary>
|
||||
/// A union type for host function argument/return values.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct ExtismValUnion
|
||||
{
|
||||
/// <summary>
|
||||
/// Set this for 32 bit integers
|
||||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
public int i32;
|
||||
|
||||
/// <summary>
|
||||
/// Set this for 64 bit integers
|
||||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
public long i64;
|
||||
|
||||
/// <summary>
|
||||
/// Set this for 32 bit floats
|
||||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
public float f32;
|
||||
|
||||
/// <summary>
|
||||
/// Set this for 64 bit floats
|
||||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
public double f64;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents Wasm data types that Extism can understand
|
||||
/// </summary>
|
||||
public enum ExtismValType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Signed 32 bit integer. Equivalent of <see cref="int"/> or <see cref="uint"/>
|
||||
/// </summary>
|
||||
I32,
|
||||
|
||||
/// <summary>
|
||||
/// Signed 64 bit integer. Equivalent of <see cref="long"/> or <see cref="ulong"/>
|
||||
/// </summary>
|
||||
I64,
|
||||
|
||||
/// <summary>
|
||||
/// Floating point 32 bit integer. Equivalent of <see cref="float"/>
|
||||
/// </summary>
|
||||
F32,
|
||||
|
||||
/// <summary>
|
||||
/// Floating point 64 bit integer. Equivalent of <see cref="double"/>
|
||||
/// </summary>
|
||||
F64,
|
||||
|
||||
/// <summary>
|
||||
/// A 128 bit number.
|
||||
/// </summary>
|
||||
V128,
|
||||
|
||||
/// <summary>
|
||||
/// A reference to opaque data in the Wasm instance.
|
||||
/// </summary>
|
||||
FuncRef,
|
||||
|
||||
/// <summary>
|
||||
/// A reference to opaque data in the Wasm instance.
|
||||
/// </summary>
|
||||
ExternRef
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// `ExtismVal` holds the type and value of a function argument/return
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ExtismVal
|
||||
{
|
||||
/// <summary>
|
||||
/// The type for the argument
|
||||
/// </summary>
|
||||
public ExtismValType t;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the argument
|
||||
/// </summary>
|
||||
public ExtismValUnion v;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Functions exposed by the native Extism library.
|
||||
/// </summary>
|
||||
internal static class LibExtism
|
||||
{
|
||||
/// <summary>
|
||||
/// An Extism Plugin
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ExtismPlugin { }
|
||||
|
||||
/// <summary>
|
||||
/// Host function signature
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <param name="inputs"></param>
|
||||
/// <param name="n_inputs"></param>
|
||||
/// <param name="outputs"></param>
|
||||
/// <param name="n_outputs"></param>
|
||||
/// <param name="data"></param>
|
||||
unsafe internal delegate void InternalExtismFunction(nint plugin, ExtismVal* inputs, uint n_inputs, ExtismVal* outputs, uint n_outputs, IntPtr data);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pointer to the memory of the currently running plugin.
|
||||
/// NOTE: this should only be called from host functions.
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism", EntryPoint = "extism_current_plugin_memory")]
|
||||
internal static extern IntPtr extism_current_plugin_memory(nint plugin);
|
||||
|
||||
/// <summary>
|
||||
/// Allocate a memory block in the currently running plugin
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <param name="n"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism", EntryPoint = "extism_current_plugin_memory_alloc")]
|
||||
internal static extern IntPtr extism_current_plugin_memory_alloc(nint plugin, long n);
|
||||
|
||||
/// <summary>
|
||||
/// Get the length of an allocated block.
|
||||
/// NOTE: this should only be called from host functions.
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <param name="n"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism", EntryPoint = "extism_current_plugin_memory_length")]
|
||||
internal static extern long extism_current_plugin_memory_length(nint plugin, long n);
|
||||
|
||||
/// <summary>
|
||||
/// Get the length of an allocated block.
|
||||
/// NOTE: this should only be called from host functions.
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <param name="ptr"></param>
|
||||
[DllImport("extism", EntryPoint = "extism_current_plugin_memory_free")]
|
||||
internal static extern void extism_current_plugin_memory_free(nint plugin, IntPtr ptr);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new host function.
|
||||
/// </summary>
|
||||
/// <param name="name">function name, this should be valid UTF-8</param>
|
||||
/// <param name="inputs">argument types</param>
|
||||
/// <param name="nInputs">number of argument types</param>
|
||||
/// <param name="outputs">return types</param>
|
||||
/// <param name="nOutputs">number of return types</param>
|
||||
/// <param name="func">the function to call</param>
|
||||
/// <param name="userData">a pointer that will be passed to the function when it's called this value should live as long as the function exists</param>
|
||||
/// <param name="freeUserData">a callback to release the `user_data` value when the resulting `ExtismFunction` is freed.</param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism", EntryPoint = "extism_function_new")]
|
||||
unsafe internal static extern IntPtr extism_function_new(string name, ExtismValType* inputs, long nInputs, ExtismValType* outputs, long nOutputs, InternalExtismFunction func, IntPtr userData, IntPtr freeUserData);
|
||||
|
||||
/// <summary>
|
||||
/// Set the namespace of an <see cref="ExtismFunction"/>
|
||||
/// </summary>
|
||||
/// <param name="ptr"></param>
|
||||
/// <param name="namespace"></param>
|
||||
[DllImport("extism", EntryPoint = "extism_function_set_namespace")]
|
||||
internal static extern void extism_function_set_namespace(IntPtr ptr, string @namespace);
|
||||
|
||||
/// <summary>
|
||||
/// Free an <see cref="ExtismFunction"/>
|
||||
/// </summary>
|
||||
/// <param name="ptr"></param>
|
||||
[DllImport("extism", EntryPoint = "extism_function_free")]
|
||||
internal static extern void extism_function_free(IntPtr ptr);
|
||||
|
||||
/// <summary>
|
||||
/// Load a WASM plugin.
|
||||
/// </summary>
|
||||
/// <param name="wasm">A WASM module (wat or wasm) or a JSON encoded manifest.</param>
|
||||
/// <param name="wasmSize">The length of the `wasm` parameter.</param>
|
||||
/// <param name="functions">Array of host function pointers.</param>
|
||||
/// <param name="nFunctions">Number of host functions.</param>
|
||||
/// <param name="withWasi">Enables/disables WASI.</param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism")]
|
||||
unsafe internal static extern ExtismPlugin* extism_plugin_new(byte* wasm, int wasmSize, IntPtr* functions, int nFunctions, bool withWasi, IntPtr* errmsg);
|
||||
|
||||
/// <summary>
|
||||
/// Remove a plugin from the registry and free associated memory.
|
||||
/// </summary>
|
||||
/// <param name="plugin">Pointer to the plugin you want to free.</param>
|
||||
[DllImport("extism")]
|
||||
unsafe internal static extern void extism_plugin_free(ExtismPlugin* plugin);
|
||||
|
||||
/// <summary>
|
||||
/// Update plugin config values, this will merge with the existing values.
|
||||
/// </summary>
|
||||
/// <param name="plugin">Pointer to the plugin you want to update the configurations for.</param>
|
||||
/// <param name="json">The configuration JSON encoded in UTF8.</param>
|
||||
/// <param name="jsonLength">The length of the `json` parameter.</param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism")]
|
||||
unsafe internal static extern bool extism_plugin_config(ExtismPlugin* plugin, byte* json, int jsonLength);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if funcName exists.
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <param name="funcName"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism")]
|
||||
unsafe internal static extern bool extism_plugin_function_exists(ExtismPlugin* plugin, string funcName);
|
||||
|
||||
/// <summary>
|
||||
/// Call a function.
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <param name="funcName">The function to call.</param>
|
||||
/// <param name="data">Input data.</param>
|
||||
/// <param name="dataLen">The length of the `data` parameter.</param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism")]
|
||||
unsafe internal static extern int extism_plugin_call(ExtismPlugin* plugin, string funcName, byte* data, int dataLen);
|
||||
|
||||
/// <summary>
|
||||
/// Get the error associated with a Plugin
|
||||
/// </summary>
|
||||
/// <param name="plugin">A plugin pointer</param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism")]
|
||||
unsafe internal static extern IntPtr extism_plugin_error(ExtismPlugin* plugin);
|
||||
|
||||
/// <summary>
|
||||
/// Get the length of a plugin's output data.
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism")]
|
||||
unsafe internal static extern long extism_plugin_output_length(ExtismPlugin* plugin);
|
||||
|
||||
/// <summary>
|
||||
/// Get the plugin's output data.
|
||||
/// </summary>
|
||||
/// <param name="plugin"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism")]
|
||||
unsafe internal static extern IntPtr extism_plugin_output_data(ExtismPlugin* plugin);
|
||||
|
||||
/// <summary>
|
||||
/// Set log file and level.
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <param name="logLevel"></param>
|
||||
/// <returns></returns>
|
||||
[DllImport("extism")]
|
||||
internal static extern bool extism_log_file(string filename, string logLevel);
|
||||
|
||||
/// <summary>
|
||||
/// Get the Extism Plugin ID, a 16-bit UUID in host order
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
// [DllImport("extism")]
|
||||
// unsafe internal static extern IntPtr extism_plugin_id(ExtismPlugin* plugin);
|
||||
|
||||
/// <summary>
|
||||
/// Extism Log Levels
|
||||
/// </summary>
|
||||
internal static class LogLevels
|
||||
{
|
||||
/// <summary>
|
||||
/// Designates very serious errors.
|
||||
/// </summary>
|
||||
internal const string Error = "Error";
|
||||
|
||||
/// <summary>
|
||||
/// Designates hazardous situations.
|
||||
/// </summary>
|
||||
internal const string Warn = "Warn";
|
||||
|
||||
/// <summary>
|
||||
/// Designates useful information.
|
||||
/// </summary>
|
||||
internal const string Info = "Info";
|
||||
|
||||
/// <summary>
|
||||
/// Designates lower priority information.
|
||||
/// </summary>
|
||||
internal const string Debug = "Debug";
|
||||
|
||||
/// <summary>
|
||||
/// Designates very low priority, often extremely verbose, information.
|
||||
/// </summary>
|
||||
internal const string Trace = "Trace";
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user