mirror of
https://github.com/extism/extism.git
synced 2026-01-13 15:57:57 -05:00
Compare commits
5 Commits
test-java-
...
fix-releas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea1c153af4 | ||
|
|
9e30cd1932 | ||
|
|
3dccf9b5cf | ||
|
|
af090dbe4d | ||
|
|
832a644e11 |
22
.github/actions/extism/action.yml
vendored
22
.github/actions/extism/action.yml
vendored
@@ -7,24 +7,12 @@ runs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
- name: Install Rust
|
- name: Download libextism
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
name: libextism-${{ matrix.os }}
|
||||||
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
|
- name: Install extism shared library
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sudo make install
|
sudo cp libextism.* /usr/local/lib
|
||||||
|
sudo cp runtime/extism.h /usr/local/include
|
||||||
36
.github/workflows/browser-ci.yml
vendored
36
.github/workflows/browser-ci.yml
vendored
@@ -1,36 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-node.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- browser/**
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
name: Browser CI
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
node:
|
|
||||||
name: Browser
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, macos-latest, windows-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
|
|
||||||
39
.github/workflows/ci-cpp.yml
vendored
39
.github/workflows/ci-cpp.yml
vendored
@@ -1,39 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-cpp.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- cpp/**
|
|
||||||
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
|
|
||||||
34
.github/workflows/ci-dotnet.yml
vendored
34
.github/workflows/ci-dotnet.yml
vendored
@@ -1,34 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-dotnet.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- dotnet/**
|
|
||||||
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
|
|
||||||
41
.github/workflows/ci-elixir.yml
vendored
41
.github/workflows/ci-elixir.yml
vendored
@@ -1,41 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-elixir.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- rust/**
|
|
||||||
- elixir/**
|
|
||||||
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
|
|
||||||
39
.github/workflows/ci-go.yml
vendored
39
.github/workflows/ci-go.yml
vendored
@@ -1,39 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-go.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- extism.go
|
|
||||||
- extism_test.go
|
|
||||||
- go.mod
|
|
||||||
- libextism.pc
|
|
||||||
- go/**
|
|
||||||
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
|
|
||||||
cd go
|
|
||||||
LD_LIBRARY_PATH=/usr/local/lib go run main.go
|
|
||||||
LD_LIBRARY_PATH=/usr/local/lib go test
|
|
||||||
47
.github/workflows/ci-haskell.yml
vendored
47
.github/workflows/ci-haskell.yml
vendored
@@ -1,47 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-haskell.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- haskell/**
|
|
||||||
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
|
|
||||||
42
.github/workflows/ci-java.yml
vendored
42
.github/workflows/ci-java.yml
vendored
@@ -1,42 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-java.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- java/**
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
name: Java CI
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
java:
|
|
||||||
name: Java
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest]
|
|
||||||
version: [8, 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
|
|
||||||
cat pom.xml | sed 's/<java.version>17/<java.version>${{ matrix.version }}/' > updated.xml
|
|
||||||
mv updated.xml pom.xml
|
|
||||||
mvn --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn verify
|
|
||||||
#- name: Examine logs
|
|
||||||
# if: success() || failure()
|
|
||||||
# run: |
|
|
||||||
# cat /tmp/extism.log
|
|
||||||
38
.github/workflows/ci-node.yml
vendored
38
.github/workflows/ci-node.yml
vendored
@@ -1,38 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-node.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- node/**
|
|
||||||
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
|
|
||||||
50
.github/workflows/ci-ocaml.yml
vendored
50
.github/workflows/ci-ocaml.yml
vendored
@@ -1,50 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-ocaml.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- ocaml/**
|
|
||||||
- dune-project
|
|
||||||
- extism.opam
|
|
||||||
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
|
|
||||||
42
.github/workflows/ci-php.yml
vendored
42
.github/workflows/ci-php.yml
vendored
@@ -1,42 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-php.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- php/**
|
|
||||||
- composer.json
|
|
||||||
- composer.lock
|
|
||||||
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
|
|
||||||
40
.github/workflows/ci-python.yml
vendored
40
.github/workflows/ci-python.yml
vendored
@@ -1,40 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-python.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- python/**
|
|
||||||
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
|
|
||||||
38
.github/workflows/ci-ruby.yml
vendored
38
.github/workflows/ci-ruby.yml
vendored
@@ -1,38 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-ruby.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- ruby/**
|
|
||||||
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
|
|
||||||
|
|
||||||
105
.github/workflows/ci-rust.yml
vendored
105
.github/workflows/ci-rust.yml
vendored
@@ -1,105 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-rust.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- rust/**
|
|
||||||
- libextism/**
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
name: Rust CI
|
|
||||||
|
|
||||||
env:
|
|
||||||
RUNTIME_CRATE: extism-runtime
|
|
||||||
LIBEXTISM_CRATE: libextism
|
|
||||||
RUST_SDK_CRATE: extism
|
|
||||||
|
|
||||||
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/**') }}
|
|
||||||
- name: Cache target
|
|
||||||
id: cache-target
|
|
||||||
uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: target/**
|
|
||||||
key: ${{ runner.os }}-target-${{ env.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-${{ env.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 --all-features --release -p ${{ env.RUNTIME_CRATE }}
|
|
||||||
|
|
||||||
rust:
|
|
||||||
name: Rust
|
|
||||||
needs: lib
|
|
||||||
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: Test Rust Host SDK
|
|
||||||
run: LD_LIBRARY_PATH=/usr/local/lib cargo test --release -p ${{ env.RUST_SDK_CRATE }}
|
|
||||||
34
.github/workflows/ci-zig.yml
vendored
34
.github/workflows/ci-zig.yml
vendored
@@ -1,34 +0,0 @@
|
|||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/actions/extism/**
|
|
||||||
- .github/workflows/ci-zig.yml
|
|
||||||
- manifest/**
|
|
||||||
- runtime/**
|
|
||||||
- libextism/**
|
|
||||||
- zig/**
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
name: Zig CI
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
zig:
|
|
||||||
name: Zig
|
|
||||||
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 Zig env
|
|
||||||
uses: goto-bus-stop/setup-zig@v2
|
|
||||||
|
|
||||||
- name: Test Zig Host SDK
|
|
||||||
run: |
|
|
||||||
zig version
|
|
||||||
cd zig
|
|
||||||
LD_LIBRARY_PATH=/usr/local/lib zig build test
|
|
||||||
355
.github/workflows/ci.yml
vendored
355
.github/workflows/ci.yml
vendored
@@ -2,7 +2,361 @@ on: [pull_request, workflow_dispatch]
|
|||||||
|
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
|
env:
|
||||||
|
RUNTIME_CRATE: extism-runtime
|
||||||
|
LIBEXTISM_CRATE: libextism
|
||||||
|
RUST_SDK_CRATE: extism
|
||||||
|
|
||||||
jobs:
|
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/**') }}
|
||||||
|
- name: Cache target
|
||||||
|
id: cache-target
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: target/**
|
||||||
|
key: ${{ runner.os }}-target-${{ env.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-${{ env.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 --all-features --release -p ${{ env.RUNTIME_CRATE }}
|
||||||
|
|
||||||
|
rust:
|
||||||
|
name: Rust
|
||||||
|
needs: lib
|
||||||
|
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: Test Rust Host SDK
|
||||||
|
run: LD_LIBRARY_PATH=/usr/local/lib cargo test --release -p ${{ env.RUST_SDK_CRATE }}
|
||||||
|
|
||||||
|
elixir:
|
||||||
|
name: Elixir
|
||||||
|
needs: lib
|
||||||
|
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
|
||||||
|
|
||||||
|
go:
|
||||||
|
name: Go
|
||||||
|
needs: lib
|
||||||
|
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
|
||||||
|
cd go
|
||||||
|
LD_LIBRARY_PATH=/usr/local/lib go run main.go
|
||||||
|
LD_LIBRARY_PATH=/usr/local/lib go test
|
||||||
|
|
||||||
|
python:
|
||||||
|
name: Python
|
||||||
|
needs: lib
|
||||||
|
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
|
||||||
|
poetry run python example.py
|
||||||
|
poetry run python -m unittest discover
|
||||||
|
|
||||||
|
ruby:
|
||||||
|
name: Ruby
|
||||||
|
needs: lib
|
||||||
|
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
|
||||||
|
|
||||||
|
node:
|
||||||
|
name: Node
|
||||||
|
needs: lib
|
||||||
|
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
|
||||||
|
|
||||||
|
- name: Test Browser Runtime
|
||||||
|
run: |
|
||||||
|
cd browser
|
||||||
|
npm i
|
||||||
|
npm run test
|
||||||
|
|
||||||
|
ocaml:
|
||||||
|
name: OCaml
|
||||||
|
needs: lib
|
||||||
|
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~beta1
|
||||||
|
- name: Cache OCaml
|
||||||
|
id: cache-ocaml
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: _build
|
||||||
|
key: ${{ runner.os }}-ocaml-${{ hashFiles('ocaml/lib/**') }}-${{ hashFiles('ocaml/bin/**') }}-${{ 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
|
||||||
|
LD_LIBRARY_PATH=/usr/local/lib opam exec -- dune runtest
|
||||||
|
|
||||||
|
haskell:
|
||||||
|
name: Haskell
|
||||||
|
needs: lib
|
||||||
|
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: true
|
||||||
|
stack-version: "latest"
|
||||||
|
- name: Cache Haskell
|
||||||
|
id: cache-haskell
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: .stack-work
|
||||||
|
key: ${{ runner.os }}-haskell-${{ hashFiles('haskell/**') }}
|
||||||
|
- name: Build Haskell Host SDK
|
||||||
|
if: steps.cache-haskell.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
cd haskell
|
||||||
|
LD_LIBRARY_PATH=/usr/local/lib stack build
|
||||||
|
- name: Test Haskell SDK
|
||||||
|
run: |
|
||||||
|
cd haskell
|
||||||
|
LD_LIBRARY_PATH=/usr/local/lib stack test
|
||||||
|
|
||||||
|
php:
|
||||||
|
name: PHP
|
||||||
|
needs: lib
|
||||||
|
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
|
||||||
|
|
||||||
|
cpp:
|
||||||
|
name: C++
|
||||||
|
needs: lib
|
||||||
|
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
|
||||||
|
|
||||||
sdk_api_coverage:
|
sdk_api_coverage:
|
||||||
name: SDK API Coverage Report
|
name: SDK API Coverage Report
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -22,4 +376,3 @@ jobs:
|
|||||||
id: coverage
|
id: coverage
|
||||||
run: |
|
run: |
|
||||||
python scripts/sdk_coverage.py
|
python scripts/sdk_coverage.py
|
||||||
|
|
||||||
|
|||||||
29
.github/workflows/release-dotnet-native.yaml
vendored
29
.github/workflows/release-dotnet-native.yaml
vendored
@@ -1,29 +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
|
|
||||||
- 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: |
|
|
||||||
tar -xvzf libextism-x86_64-pc-windows-msvc-v*.tar.gz --directory dotnet/nuget/runtimes
|
|
||||||
mv dotnet/nuget/runtimes/extism.dll dotnet/nuget/runtimes/win-x64.dll
|
|
||||||
- name: Publish win-x64
|
|
||||||
run: |
|
|
||||||
cd dotnet/nuget
|
|
||||||
dotnet pack -o dist
|
|
||||||
dotnet nuget push --source https://api.nuget.org/v3/index.json ./dist/*.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 }}
|
|
||||||
8
.github/workflows/release-elixir.yaml
vendored
8
.github/workflows/release-elixir.yaml
vendored
@@ -10,13 +10,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
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
|
- name: Setup Elixir Host SDK
|
||||||
uses: erlef/setup-beam@v1
|
uses: erlef/setup-beam@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
17
.github/workflows/release-haskell.yaml
vendored
17
.github/workflows/release-haskell.yaml
vendored
@@ -1,17 +0,0 @@
|
|||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
name: Release Rust 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
|
|
||||||
3
.github/workflows/release-python.yaml
vendored
3
.github/workflows/release-python.yaml
vendored
@@ -23,8 +23,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd python
|
cd python
|
||||||
cp ../LICENSE .
|
cp ../LICENSE .
|
||||||
|
cp ../README.md .
|
||||||
make clean
|
make clean
|
||||||
poetry install --no-dev
|
make prepare
|
||||||
poetry build
|
poetry build
|
||||||
|
|
||||||
- name: Release Python Host SDK
|
- name: Release Python Host SDK
|
||||||
|
|||||||
2
.github/workflows/release-ruby.yaml
vendored
2
.github/workflows/release-ruby.yaml
vendored
@@ -21,5 +21,5 @@ jobs:
|
|||||||
RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_TOKEN }}
|
RUBYGEMS_API_KEY: ${{ secrets.RUBYGEMS_API_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
cd ruby
|
cd ruby
|
||||||
make publish RUBYGEMS_API_KEY=$RUBYGEMS_API_KEY
|
make publish
|
||||||
|
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -27,12 +27,9 @@ ruby/tmp/
|
|||||||
ruby/Gemfile.lock
|
ruby/Gemfile.lock
|
||||||
rust/target
|
rust/target
|
||||||
rust/test.log
|
rust/test.log
|
||||||
duniverse
|
ocaml/duniverse
|
||||||
_build
|
ocaml/_build
|
||||||
php/Extism.php
|
php/Extism.php
|
||||||
dist-newstyle
|
dist-newstyle
|
||||||
.stack-work
|
.stack-work
|
||||||
vendor
|
vendor
|
||||||
zig/zig-*
|
|
||||||
zig/example-out/
|
|
||||||
zig/*.log
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
version = 0.24.1
|
|
||||||
@@ -3,6 +3,8 @@ members = [
|
|||||||
"manifest",
|
"manifest",
|
||||||
"runtime",
|
"runtime",
|
||||||
"rust",
|
"rust",
|
||||||
"libextism",
|
"libextism"
|
||||||
|
]
|
||||||
|
exclude = [
|
||||||
"elixir/native/extism_nif"
|
"elixir/native/extism_nif"
|
||||||
]
|
]
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -27,9 +27,6 @@ lint:
|
|||||||
build:
|
build:
|
||||||
cargo build --release $(FEATURE_FLAGS) --manifest-path libextism/Cargo.toml
|
cargo build --release $(FEATURE_FLAGS) --manifest-path libextism/Cargo.toml
|
||||||
|
|
||||||
debug:
|
|
||||||
RUSTFLAGS=-g $(MAKE) build
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
install runtime/extism.h $(DEST)/include
|
install runtime/extism.h $(DEST)/include
|
||||||
install target/release/libextism.$(SOEXT) $(DEST)/lib
|
install target/release/libextism.$(SOEXT) $(DEST)/lib
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -10,21 +10,16 @@ The universal plug-in system. Run WebAssembly extensions inside your app. Use id
|
|||||||
[Ruby](https://extism.org/docs/integrate-into-your-codebase/ruby-host-sdk), [Python](https://extism.org/docs/integrate-into-your-codebase/python-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),
|
[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),
|
[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),
|
[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), [Elixir/Erlang](https://extism.org/docs/integrate-into-your-codebase/elixir-or-erlang-host-sdk) & more (others coming soon).
|
||||||
[Haskell](https://extism.org/docs/integrate-into-your-codebase/haskell-host-sdk),
|
|
||||||
[PHP](https://extism.org/docs/integrate-into-your-codebase/php-host-sdk),
|
|
||||||
[Elixir/Erlang](https://extism.org/docs/integrate-into-your-codebase/elixir-or-erlang-host-sdk),
|
|
||||||
[.NET](https://extism.org/docs/integrate-into-your-codebase/dotnet-host-sdk),
|
|
||||||
[Java](https://extism.org/docs/integrate-into-your-codebase/java-host-sdk),
|
|
||||||
[Zig](https://extism.org/docs/integrate-into-your-codebase/zig-host-sdk) & more (others coming soon).
|
|
||||||
|
|
||||||
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), [Haskell](https://github.com/extism/haskell-pdk), and [Zig](https://github.com/extism/zig-pdk).
|
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">
|
<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/200043015-ddfe5833-0252-43a8-bc9e-5b3f829c37d1.png" alt="Extism embedded SDK language support"/>
|
||||||
</p>
|
</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:**
|
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
|
### 1. Import
|
||||||
|
|||||||
@@ -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,12 +1,12 @@
|
|||||||
const { build } = require("esbuild");
|
const { build } = require("esbuild");
|
||||||
const { peerDependencies } = require('./package.json')
|
const { dependencies, peerDependencies } = require('./package.json')
|
||||||
|
|
||||||
const sharedConfig = {
|
const sharedConfig = {
|
||||||
entryPoints: ["src/index.ts"],
|
entryPoints: ["src/index.ts"],
|
||||||
bundle: true,
|
bundle: true,
|
||||||
minify: false,
|
minify: false,
|
||||||
drop: [], // preseve debugger statements
|
drop: [], // preseve debugger statements
|
||||||
external: Object.keys(peerDependencies || {}),
|
external: Object.keys(dependencies || {}).concat(Object.keys(peerDependencies || {})),
|
||||||
};
|
};
|
||||||
|
|
||||||
build({
|
build({
|
||||||
|
|||||||
@@ -104,7 +104,7 @@
|
|||||||
|
|
||||||
async loadFunctions(url) {
|
async loadFunctions(url) {
|
||||||
let plugin = await this.extismContext.newPlugin({ "wasm": [ { "path": url } ] })
|
let plugin = await this.extismContext.newPlugin({ "wasm": [ { "path": url } ] })
|
||||||
let functions = Object.keys(await plugin.getExports())
|
let functions = await plugin.getExportedFunctions()
|
||||||
console.log("funcs ", functions)
|
console.log("funcs ", functions)
|
||||||
this.setState({functions})
|
this.setState({functions})
|
||||||
}
|
}
|
||||||
|
|||||||
1040
browser/package-lock.json
generated
1040
browser/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@extism/runtime-browser",
|
"name": "@extism/runtime-browser",
|
||||||
"version": "0.2.2",
|
"version": "0.0.1",
|
||||||
"description": "Extism runtime in the browser",
|
"description": "Extism runtime in the browser",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node build.js && tsc --emitDeclarationOnly --outDir dist",
|
"build": "node build.js && tsc --emitDeclarationOnly --outDir dist",
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
],
|
],
|
||||||
"module": "dist/index.esm.js",
|
"module": "dist/index.esm.js",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"typings": "dist/src/index.d.ts",
|
"typings": "dist/index.d.ts",
|
||||||
"author": "The Extism Authors <oss@extism.org>",
|
"author": "The Extism Authors <oss@extism.org>",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -30,8 +30,5 @@
|
|||||||
"tslint-config-prettier": "^1.18.0",
|
"tslint-config-prettier": "^1.18.0",
|
||||||
"typedoc": "^0.23.20",
|
"typedoc": "^0.23.20",
|
||||||
"typescript": "^4.8.4"
|
"typescript": "^4.8.4"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@bjorn3/browser_wasi_shim": "^0.2.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe('', () => {
|
|||||||
const ctx = new ExtismContext();
|
const ctx = new ExtismContext();
|
||||||
const plugin = await ctx.newPlugin({ wasm: [{ data: data }] });
|
const plugin = await ctx.newPlugin({ wasm: [{ data: data }] });
|
||||||
const functions = await plugin.getExports();
|
const functions = await plugin.getExports();
|
||||||
expect(Object.keys(functions).filter((x) => !x.startsWith('__') && x !== 'memory')).toEqual(['count_vowels']);
|
expect(Object.keys(functions).filter(x => !x.startsWith("__") && x !== "memory")).toEqual(['count_vowels']);
|
||||||
let output = await plugin.call('count_vowels', 'this is a test');
|
let output = await plugin.call('count_vowels', 'this is a test');
|
||||||
expect(parse(output)).toEqual({ count: 4 });
|
expect(parse(output)).toEqual({ count: 4 });
|
||||||
output = await plugin.call('count_vowels', 'this is a test again');
|
output = await plugin.call('count_vowels', 'this is a test again');
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import Allocator from './allocator';
|
import Allocator from './allocator';
|
||||||
import { PluginConfig } from './manifest';
|
import { PluginConfig } from './manifest';
|
||||||
//@ts-ignore TODO add types to this library
|
|
||||||
import { WASI, File } from "@bjorn3/browser_wasi_shim";
|
|
||||||
|
|
||||||
export default class ExtismPlugin {
|
export default class ExtismPlugin {
|
||||||
moduleData: ArrayBuffer;
|
moduleData: ArrayBuffer;
|
||||||
@@ -63,19 +61,7 @@ export default class ExtismPlugin {
|
|||||||
return this.module;
|
return this.module;
|
||||||
}
|
}
|
||||||
const environment = this.makeEnv();
|
const environment = this.makeEnv();
|
||||||
const args: Array<string> = [];
|
this.module = await WebAssembly.instantiate(this.moduleData, { env: environment });
|
||||||
const envVars: Array<string> = [];
|
|
||||||
let fds = [
|
|
||||||
new File([]), // stdin
|
|
||||||
new File([]), // stdout
|
|
||||||
new File([]), // stderr
|
|
||||||
];
|
|
||||||
let wasi = new WASI(args, envVars, fds);
|
|
||||||
let env = {
|
|
||||||
wasi_snapshot_preview1: wasi.wasiImport,
|
|
||||||
env: environment
|
|
||||||
};
|
|
||||||
this.module = await WebAssembly.instantiate(this.moduleData, env);
|
|
||||||
return this.module;
|
return this.module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true
|
||||||
"allowJs": true
|
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
1
c/main.c
1
c/main.c
@@ -21,7 +21,6 @@ uint8_t *read_file(const char *filename, size_t *len) {
|
|||||||
|
|
||||||
uint8_t *data = malloc(length);
|
uint8_t *data = malloc(length);
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
fclose(fp);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"php/src/Context.php",
|
"php/src/Context.php",
|
||||||
"php/src/Plugin.php"
|
"php/src/Plugin.php",
|
||||||
|
"php/src/extism.h"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
|
|||||||
@@ -53,10 +53,6 @@ public:
|
|||||||
Config config;
|
Config config;
|
||||||
std::vector<Wasm> wasm;
|
std::vector<Wasm> wasm;
|
||||||
std::vector<std::string> allowed_hosts;
|
std::vector<std::string> allowed_hosts;
|
||||||
std::map<std::string, std::string> allowed_paths;
|
|
||||||
uint64_t timeout_ms;
|
|
||||||
|
|
||||||
Manifest() : timeout_ms(30000) {}
|
|
||||||
|
|
||||||
static Manifest path(std::string s, std::string hash = std::string()) {
|
static Manifest path(std::string s, std::string hash = std::string()) {
|
||||||
Manifest m;
|
Manifest m;
|
||||||
@@ -98,16 +94,6 @@ public:
|
|||||||
doc["allowed_hosts"] = h;
|
doc["allowed_hosts"] = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->allowed_paths.empty()) {
|
|
||||||
Json::Value h;
|
|
||||||
for (auto k : this->allowed_paths) {
|
|
||||||
h[k.first] = k.second;
|
|
||||||
}
|
|
||||||
doc["allowed_paths"] = h;
|
|
||||||
}
|
|
||||||
|
|
||||||
doc["timeout_ms"] = Json::Value(this->timeout_ms);
|
|
||||||
|
|
||||||
Json::FastWriter writer;
|
Json::FastWriter writer;
|
||||||
return writer.write(doc);
|
return writer.write(doc);
|
||||||
}
|
}
|
||||||
@@ -129,15 +115,6 @@ public:
|
|||||||
|
|
||||||
void allow_host(std::string host) { this->allowed_hosts.push_back(host); }
|
void allow_host(std::string host) { this->allowed_hosts.push_back(host); }
|
||||||
|
|
||||||
void allow_path(std::string src, std::string dest = std::string()) {
|
|
||||||
if (dest.empty()) {
|
|
||||||
dest = src;
|
|
||||||
}
|
|
||||||
this->allowed_paths[src] = dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_timeout_ms(uint64_t ms) { this->timeout_ms = ms; }
|
|
||||||
|
|
||||||
void set_config(std::string k, std::string v) { this->config[k] = v; }
|
void set_config(std::string k, std::string v) { this->config[k] = v; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -289,7 +266,6 @@ public:
|
|||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<ExtismContext> pointer;
|
std::shared_ptr<ExtismContext> pointer;
|
||||||
|
|
||||||
Context() {
|
Context() {
|
||||||
this->pointer = std::shared_ptr<ExtismContext>(extism_context_new(),
|
this->pointer = std::shared_ptr<ExtismContext>(extism_context_new(),
|
||||||
extism_context_free);
|
extism_context_free);
|
||||||
|
|||||||
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,24 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
|
|
||||||
<NoBuild>true</NoBuild>
|
|
||||||
<IncludeBuildOutput>false</IncludeBuildOutput>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<PackageId>Extism.runtime.win-x64</PackageId>
|
|
||||||
<Version>0.2.0</Version>
|
|
||||||
<Authors>Extism Contributors</Authors>
|
|
||||||
<Description>Internal implementation package for Extism to work on Windows x64</Description>
|
|
||||||
<Tags>extism, wasm, plugin</Tags>
|
|
||||||
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="runtimes/win-x64.dll"
|
|
||||||
CopyToOutputDirectory="Always"
|
|
||||||
Pack="true"
|
|
||||||
PackagePath="runtimes\win-x64\native\extism.dll" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
win-x64.dll
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\..\..\wasm\code.wasm" Link="code.wasm">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\src\Extism.Sdk\Extism.Sdk.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Extism.Sdk.Native;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
var context = new Context();
|
|
||||||
var wasm = await File.ReadAllBytesAsync("./code.wasm");
|
|
||||||
using var plugin = context.CreatePlugin(wasm, withWasi: true);
|
|
||||||
|
|
||||||
var output = Encoding.UTF8.GetString(
|
|
||||||
plugin.CallFunction("count_vowels", Encoding.UTF8.GetBytes("Hello World!"))
|
|
||||||
);
|
|
||||||
Console.WriteLine(output); // prints {"count": 3}
|
|
||||||
@@ -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,184 +0,0 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Extism.Sdk.Native;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an Extism context through which you can load <see cref="Plugin"/>s.
|
|
||||||
/// </summary>
|
|
||||||
public class Context : IDisposable
|
|
||||||
{
|
|
||||||
private const int DisposedMarker = 1;
|
|
||||||
|
|
||||||
private int _disposed;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize a new Extism Context.
|
|
||||||
/// </summary>
|
|
||||||
public Context()
|
|
||||||
{
|
|
||||||
NativeHandle = LibExtism.extism_context_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Native pointer to the Extism Context.
|
|
||||||
/// </summary>
|
|
||||||
internal IntPtr NativeHandle { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads an Extism <see cref="Plugin"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="wasm">A WASM module (wat or wasm) or a JSON encoded manifest.</param>
|
|
||||||
/// <param name="withWasi">Enable/Disable WASI.</param>
|
|
||||||
public Plugin CreatePlugin(ReadOnlySpan<byte> wasm, bool withWasi)
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
fixed (byte* wasmPtr = wasm)
|
|
||||||
{
|
|
||||||
var plugin = LibExtism.extism_plugin_new(NativeHandle, wasmPtr, wasm.Length, withWasi);
|
|
||||||
return new Plugin(this, plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove all plugins from this <see cref="Context"/>'s registry.
|
|
||||||
/// </summary>
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
LibExtism.extism_context_reset(NativeHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get this this <see cref="Context"/>'s last error.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal string? GetError()
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
var result = LibExtism.extism_error(NativeHandle, -1);
|
|
||||||
return Marshal.PtrToStringUTF8(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Frees all resources held by this Context.
|
|
||||||
/// </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 plugin 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(Context));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Frees all resources held by this Context.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
// Free up any managed resources here
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free up unmanaged resources
|
|
||||||
LibExtism.extism_context_free(NativeHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Destructs the current Context and frees all resources used by it.
|
|
||||||
/// </summary>
|
|
||||||
~Context()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the Extism version string.
|
|
||||||
/// </summary>
|
|
||||||
public static string GetExtismVersion()
|
|
||||||
{
|
|
||||||
var pointer = LibExtism.extism_version();
|
|
||||||
return Marshal.PtrToStringUTF8(pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set Extism's log file and level. This is applied for all <see cref="Context"/>s.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="logPath">Log file; can be 'stdout' or 'stderr' to write logs to the console.</param>
|
|
||||||
/// <param name="level">The log level to write at.</param>
|
|
||||||
public static bool SetExtismLogFile(string logPath, LogLevel level)
|
|
||||||
{
|
|
||||||
var logLevel = level switch
|
|
||||||
{
|
|
||||||
LogLevel.Error => LibExtism.LogLevels.Error,
|
|
||||||
LogLevel.Warning => LibExtism.LogLevels.Warn,
|
|
||||||
LogLevel.Info => LibExtism.LogLevels.Info,
|
|
||||||
LogLevel.Debug => LibExtism.LogLevels.Debug,
|
|
||||||
LogLevel.Trace => LibExtism.LogLevels.Trace,
|
|
||||||
_ => throw new NotImplementedException(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return LibExtism.extism_log_file(logPath, logLevel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extism Log Levels
|
|
||||||
/// </summary>
|
|
||||||
public enum LogLevel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Designates very serious errors.
|
|
||||||
/// </summary>
|
|
||||||
Error,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Designates hazardous situations.
|
|
||||||
/// </summary>
|
|
||||||
Warning,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Designates useful information.
|
|
||||||
/// </summary>
|
|
||||||
Info,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Designates lower priority information.
|
|
||||||
/// </summary>
|
|
||||||
Debug,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Designates very low priority, often extremely verbose, information.
|
|
||||||
/// </summary>
|
|
||||||
Trace
|
|
||||||
}
|
|
||||||
@@ -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,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.2.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,170 +0,0 @@
|
|||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Extism.Sdk.Native;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Functions exposed by the native Extism library.
|
|
||||||
/// </summary>
|
|
||||||
internal static class LibExtism
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new context.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A pointer to the newly created context.</returns>
|
|
||||||
[DllImport("extism")]
|
|
||||||
public static extern IntPtr extism_context_new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a context from the registry and free associated memory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
[DllImport("extism")]
|
|
||||||
public static extern void extism_context_free(IntPtr context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Load a WASM plugin.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Pointer to the context the plugin will be associated with.</param>
|
|
||||||
/// <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="withWasi">Enables/disables WASI.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DllImport("extism")]
|
|
||||||
unsafe public static extern IntPtr extism_plugin_new(IntPtr context, byte* wasm, int wasmSize, bool withWasi);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update a plugin, keeping the existing ID.
|
|
||||||
/// Similar to <see cref="extism_plugin_new"/> but takes an `plugin` argument to specify which plugin to update.
|
|
||||||
/// Memory for this plugin will be reset upon update.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Pointer to the context the plugin is associated with.</param>
|
|
||||||
/// <param name="plugin">Pointer to the plugin you want to update.</param>
|
|
||||||
/// <param name="wasm">A WASM module (wat or wasm) or a JSON encoded manifest.</param>
|
|
||||||
/// <param name="wasmLength">The length of the `wasm` parameter.</param>
|
|
||||||
/// <param name="withWasi">Enables/disables WASI.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DllImport("extism")]
|
|
||||||
unsafe public static extern bool extism_plugin_update(IntPtr context, IntPtr plugin, byte* wasm, int wasmLength, bool withWasi);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a plugin from the registry and free associated memory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Pointer to the context the plugin is associated with.</param>
|
|
||||||
/// <param name="plugin">Pointer to the plugin you want to free.</param>
|
|
||||||
[DllImport("extism")]
|
|
||||||
public static extern void extism_plugin_free(IntPtr context, IntPtr plugin);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove all plugins from the registry.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
[DllImport("extism")]
|
|
||||||
public static extern void extism_context_reset(IntPtr context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update plugin config values, this will merge with the existing values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Pointer to the context the plugin is associated with.</param>
|
|
||||||
/// <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 public static extern bool extism_plugin_config(IntPtr context, IntPtr plugin, byte* json, int jsonLength);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns true if funcName exists.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="plugin"></param>
|
|
||||||
/// <param name="funcName"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DllImport("extism")]
|
|
||||||
public static extern bool extism_plugin_function_exists(IntPtr context, IntPtr plugin, string funcName);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Call a function.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <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 public static extern int extism_plugin_call(IntPtr context, IntPtr plugin, string funcName, byte* data, int dataLen);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the error associated with a Context or Plugin, if plugin is -1 then the context error will be returned.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="plugin">A plugin pointer, or -1 for the context error.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DllImport("extism")]
|
|
||||||
public static extern IntPtr extism_error(IntPtr context, nint plugin);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the length of a plugin's output data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="plugin"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DllImport("extism")]
|
|
||||||
public static extern long extism_plugin_output_length(IntPtr context, IntPtr plugin);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the plugin's output data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="plugin"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DllImport("extism")]
|
|
||||||
public static extern IntPtr extism_plugin_output_data(IntPtr context, IntPtr plugin);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set log file and level.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename"></param>
|
|
||||||
/// <param name="logLevel"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DllImport("extism")]
|
|
||||||
public static extern bool extism_log_file(string filename, string logLevel);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the Extism version string.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DllImport("extism", EntryPoint = "extism_version")]
|
|
||||||
public static extern IntPtr extism_version();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extism Log Levels
|
|
||||||
/// </summary>
|
|
||||||
public static class LogLevels
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Designates very serious errors.
|
|
||||||
/// </summary>
|
|
||||||
public const string Error = "Error";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Designates hazardous situations.
|
|
||||||
/// </summary>
|
|
||||||
public const string Warn = "Warn";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Designates useful information.
|
|
||||||
/// </summary>
|
|
||||||
public const string Info = "Info";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Designates lower priority information.
|
|
||||||
/// </summary>
|
|
||||||
public const string Debug = "Debug";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Designates very low priority, often extremely verbose, information.
|
|
||||||
/// </summary>
|
|
||||||
public const string Trace = "Trace";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Extism.Sdk.Native;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a WASM Extism plugin.
|
|
||||||
/// </summary>
|
|
||||||
public class Plugin : IDisposable
|
|
||||||
{
|
|
||||||
private const int DisposedMarker = 1;
|
|
||||||
|
|
||||||
private readonly Context _context;
|
|
||||||
private int _disposed;
|
|
||||||
|
|
||||||
internal Plugin(Context context, IntPtr handle)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
NativeHandle = handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A pointer to the native Plugin struct.
|
|
||||||
/// </summary>
|
|
||||||
internal IntPtr NativeHandle { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update a plugin, keeping the existing ID.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="wasm">The plugin WASM bytes.</param>
|
|
||||||
/// <param name="withWasi">Enable/Disable WASI.</param>
|
|
||||||
unsafe public bool Update(ReadOnlySpan<byte> wasm, bool withWasi)
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
fixed (byte* wasmPtr = wasm)
|
|
||||||
{
|
|
||||||
return LibExtism.extism_plugin_update(_context.NativeHandle, NativeHandle, wasmPtr, wasm.Length, withWasi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update plugin config values, this will merge with the existing values.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="json">The configuration JSON encoded in UTF8.</param>
|
|
||||||
unsafe public bool SetConfig(ReadOnlySpan<byte> json)
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
fixed (byte* jsonPtr = json)
|
|
||||||
{
|
|
||||||
return LibExtism.extism_plugin_config(_context.NativeHandle, NativeHandle, jsonPtr, json.Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if a specific function exists in the current plugin.
|
|
||||||
/// </summary>
|
|
||||||
public bool FunctionExists(string name)
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
return LibExtism.extism_plugin_function_exists(_context.NativeHandle, NativeHandle, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calls a function in the current plugin and returns a status.
|
|
||||||
/// If the status represents an error, call <see cref="GetError"/> to get the error.
|
|
||||||
/// Othewise, call <see cref="OutputData"/> to get the function's output data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="functionName">Name of the function in the plugin to invoke.</param>
|
|
||||||
/// <param name="data">A buffer to provide as input to the function.</param>
|
|
||||||
/// <returns>The exit code of the function.</returns>
|
|
||||||
/// <exception cref="ExtismException"></exception>
|
|
||||||
unsafe public ReadOnlySpan<byte> CallFunction(string functionName, ReadOnlySpan<byte> data)
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
fixed (byte* dataPtr = data)
|
|
||||||
{
|
|
||||||
int response = LibExtism.extism_plugin_call(_context.NativeHandle, NativeHandle, functionName, dataPtr, data.Length);
|
|
||||||
if (response == 0) {
|
|
||||||
return OutputData();
|
|
||||||
} else {
|
|
||||||
var errorMsg = GetError();
|
|
||||||
if (errorMsg != null) {
|
|
||||||
throw new ExtismException(errorMsg);
|
|
||||||
} else {
|
|
||||||
throw new ExtismException("Call to Extism failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the length of a plugin's output data.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal int OutputLength()
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
return (int)LibExtism.extism_plugin_output_length(_context.NativeHandle, NativeHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the plugin's output data.
|
|
||||||
/// </summary>
|
|
||||||
internal ReadOnlySpan<byte> OutputData()
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
var length = OutputLength();
|
|
||||||
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
var ptr = LibExtism.extism_plugin_output_data(_context.NativeHandle, NativeHandle).ToPointer();
|
|
||||||
return new Span<byte>(ptr, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the error associated with the current plugin.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal string? GetError()
|
|
||||||
{
|
|
||||||
CheckNotDisposed();
|
|
||||||
|
|
||||||
var result = LibExtism.extism_error(_context.NativeHandle, NativeHandle);
|
|
||||||
return Marshal.PtrToStringUTF8(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Frees all resources held by this Plugin.
|
|
||||||
/// </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 plugin 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(Plugin));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Frees all resources held by this Plugin.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
// Free up any managed resources here
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free up unmanaged resources
|
|
||||||
LibExtism.extism_plugin_free(_context.NativeHandle, NativeHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Destructs the current Plugin and frees all resources used by it.
|
|
||||||
/// </summary>
|
|
||||||
~Plugin()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
## Extism.Sdk
|
|
||||||
Extism SDK that allows hosting Extism plugins in .NET apps.
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Extism.Sdk.Native;
|
|
||||||
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Extism.Sdk.Tests;
|
|
||||||
|
|
||||||
public class BasicTests
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public void CountHelloWorldVowels()
|
|
||||||
{
|
|
||||||
using var context = new Context();
|
|
||||||
|
|
||||||
var binDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
|
|
||||||
var wasm = File.ReadAllBytes(Path.Combine(binDirectory, "code.wasm"));
|
|
||||||
using var plugin = context.CreatePlugin(wasm, withWasi: true);
|
|
||||||
|
|
||||||
var response = plugin.CallFunction("count_vowels", Encoding.UTF8.GetBytes("Hello World"));
|
|
||||||
Assert.Equal("{\"count\": 3}", Encoding.UTF8.GetString(response));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
|
||||||
<PackageReference Include="xunit" Version="2.4.2" />
|
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\..\..\wasm\code.wasm" Link="code.wasm">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\src\Extism.Sdk\Extism.Sdk.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
24
dune-project
24
dune-project
@@ -19,28 +19,6 @@
|
|||||||
(name extism)
|
(name extism)
|
||||||
(synopsis "Extism bindings")
|
(synopsis "Extism bindings")
|
||||||
(description "Bindings to Extism, the universal plugin system")
|
(description "Bindings to Extism, the universal plugin system")
|
||||||
(depends
|
(depends ocaml dune ctypes-foreign bigstringaf ppx_yojson_conv base64 ppx_inline_test)
|
||||||
(ocaml (>= 4.14.1))
|
|
||||||
(dune (>= 3.2))
|
|
||||||
(ctypes-foreign (>= 0.18.0))
|
|
||||||
(bigstringaf (>= 0.9.0))
|
|
||||||
(ppx_yojson_conv (>= 0.15.0))
|
|
||||||
extism-manifest
|
|
||||||
(ppx_inline_test (>= 0.15.0))
|
|
||||||
(cmdliner (>= 1.1.1))
|
|
||||||
)
|
|
||||||
(tags
|
|
||||||
(topics wasm plugin)))
|
|
||||||
|
|
||||||
(package
|
|
||||||
(name extism-manifest)
|
|
||||||
(synopsis "Extism manifest bindings")
|
|
||||||
(description "Bindings to Extism, the universal plugin system")
|
|
||||||
(depends
|
|
||||||
(ocaml (>= 4.14.1))
|
|
||||||
(dune (>= 3.2))
|
|
||||||
(ppx_yojson_conv (>= 0.15.0))
|
|
||||||
(base64 (>= 3.5.0))
|
|
||||||
)
|
|
||||||
(tags
|
(tags
|
||||||
(topics wasm plugin)))
|
(topics wasm plugin)))
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ You can find this package on [hex.pm](https://hex.pm/packages/extism).
|
|||||||
```elixir
|
```elixir
|
||||||
def deps do
|
def deps do
|
||||||
[
|
[
|
||||||
{:extism, "~> 0.1.0"}
|
{:extism, "~> 0.0.1-rc.6"}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
@@ -70,4 +70,4 @@ The key method to know here is [Extism.Plugin#call](Extism.Plugin.html#call/3) w
|
|||||||
```elixir
|
```elixir
|
||||||
{:ok, plugin} = Extism.Context.new_plugin(ctx, manifest, false)
|
{:ok, plugin} = Extism.Context.new_plugin(ctx, manifest, false)
|
||||||
{:ok, output} = Extism.Plugin.call(plugin, "count_vowels", "this is a test")
|
{:ok, output} = Extism.Plugin.call(plugin, "count_vowels", "this is a test")
|
||||||
```
|
```
|
||||||
@@ -4,8 +4,8 @@ defmodule Extism.MixProject do
|
|||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :extism,
|
app: :extism,
|
||||||
version: "0.1.0",
|
version: "0.0.1",
|
||||||
elixir: "~> 1.12",
|
elixir: "~> 1.14",
|
||||||
start_permanent: Mix.env() == :prod,
|
start_permanent: Mix.env() == :prod,
|
||||||
deps: deps(),
|
deps: deps(),
|
||||||
package: package(),
|
package: package(),
|
||||||
@@ -43,7 +43,7 @@ defmodule Extism.MixProject do
|
|||||||
licenses: ["BSD-3-Clause"],
|
licenses: ["BSD-3-Clause"],
|
||||||
description: "Extism Host SDK for Elixir and Erlang",
|
description: "Extism Host SDK for Elixir and Erlang",
|
||||||
name: "extism",
|
name: "extism",
|
||||||
files: ~w(lib native .formatter.exs mix.exs README.md LICENSE),
|
files: ~w(lib native priv .formatter.exs mix.exs README.md LICENSE),
|
||||||
links: %{"GitHub" => "https://github.com/extism/extism"}
|
links: %{"GitHub" => "https://github.com/extism/extism"}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "extism_nif"
|
name = "extism_nif"
|
||||||
version = "0.1.0"
|
version = "0.0.1-rc.6"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Benjamin Eckel <bhelx@simst.im>"]
|
authors = ["Benjamin Eckel <bhelx@simst.im>"]
|
||||||
|
|
||||||
@@ -11,5 +11,5 @@ crate-type = ["cdylib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustler = "0.26.0"
|
rustler = "0.26.0"
|
||||||
extism = { version = "0.1.0", path = "../../../rust" }
|
extism = { version = "0.0.1-rc.6" }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use extism::{Context, Plugin};
|
use rustler::{Atom, Env, Term, ResourceArc};
|
||||||
use rustler::{Atom, Env, ResourceArc, Term};
|
use extism::{Plugin, Context};
|
||||||
use std::mem;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::str;
|
use std::str;
|
||||||
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
mod atoms {
|
mod atoms {
|
||||||
rustler::atoms! {
|
rustler::atoms! {
|
||||||
@@ -15,12 +15,9 @@ mod atoms {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ExtismContext {
|
struct ExtismContext {
|
||||||
ctx: RwLock<Context>,
|
ctx: RwLock<Context>
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Sync for ExtismContext {}
|
|
||||||
unsafe impl Send for ExtismContext {}
|
|
||||||
|
|
||||||
fn load(env: Env, _: Term) -> bool {
|
fn load(env: Env, _: Term) -> bool {
|
||||||
rustler::resource!(ExtismContext, env);
|
rustler::resource!(ExtismContext, env);
|
||||||
true
|
true
|
||||||
@@ -30,16 +27,15 @@ fn to_rustler_error(extism_error: extism::Error) -> rustler::Error {
|
|||||||
match extism_error {
|
match extism_error {
|
||||||
extism::Error::UnableToLoadPlugin(msg) => rustler::Error::Term(Box::new(msg)),
|
extism::Error::UnableToLoadPlugin(msg) => rustler::Error::Term(Box::new(msg)),
|
||||||
extism::Error::Message(msg) => rustler::Error::Term(Box::new(msg)),
|
extism::Error::Message(msg) => rustler::Error::Term(Box::new(msg)),
|
||||||
extism::Error::Json(json_err) => rustler::Error::Term(Box::new(json_err.to_string())),
|
extism::Error::Json(json_err) => rustler::Error::Term(Box::new(json_err.to_string()))
|
||||||
extism::Error::Runtime(e) => rustler::Error::Term(Box::new(e.to_string())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustler::nif]
|
#[rustler::nif]
|
||||||
fn context_new() -> ResourceArc<ExtismContext> {
|
fn context_new() -> ResourceArc<ExtismContext> {
|
||||||
ResourceArc::new(ExtismContext {
|
ResourceArc::new(
|
||||||
ctx: RwLock::new(Context::new()),
|
ExtismContext { ctx: RwLock::new(Context::new()) }
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustler::nif]
|
#[rustler::nif]
|
||||||
@@ -55,11 +51,7 @@ fn context_free(ctx: ResourceArc<ExtismContext>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rustler::nif]
|
#[rustler::nif]
|
||||||
fn plugin_new_with_manifest(
|
fn plugin_new_with_manifest(ctx: ResourceArc<ExtismContext>, manifest_payload: String, wasi: bool) -> Result<i32, rustler::Error> {
|
||||||
ctx: ResourceArc<ExtismContext>,
|
|
||||||
manifest_payload: String,
|
|
||||||
wasi: bool,
|
|
||||||
) -> Result<i32, rustler::Error> {
|
|
||||||
let context = &ctx.ctx.write().unwrap();
|
let context = &ctx.ctx.write().unwrap();
|
||||||
let result = match Plugin::new(context, manifest_payload, wasi) {
|
let result = match Plugin::new(context, manifest_payload, wasi) {
|
||||||
Err(e) => Err(to_rustler_error(e)),
|
Err(e) => Err(to_rustler_error(e)),
|
||||||
@@ -75,22 +67,17 @@ fn plugin_new_with_manifest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rustler::nif]
|
#[rustler::nif]
|
||||||
fn plugin_call(
|
fn plugin_call(ctx: ResourceArc<ExtismContext>, plugin_id: i32, name: String, input: String) -> Result<String, rustler::Error> {
|
||||||
ctx: ResourceArc<ExtismContext>,
|
|
||||||
plugin_id: i32,
|
|
||||||
name: String,
|
|
||||||
input: String,
|
|
||||||
) -> Result<String, rustler::Error> {
|
|
||||||
let context = &ctx.ctx.read().unwrap();
|
let context = &ctx.ctx.read().unwrap();
|
||||||
let mut plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
let plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
||||||
let result = match plugin.call(name, input) {
|
let result = match plugin.call(name, input) {
|
||||||
Err(e) => Err(to_rustler_error(e)),
|
Err(e) => Err(to_rustler_error(e)),
|
||||||
Ok(result) => match str::from_utf8(&result) {
|
Ok(result) => {
|
||||||
Ok(output) => Ok(output.to_string()),
|
match str::from_utf8(&result) {
|
||||||
Err(_e) => Err(rustler::Error::Term(Box::new(
|
Ok(output) => Ok(output.to_string()),
|
||||||
"Could not read output from plugin",
|
Err(_e) => Err(rustler::Error::Term(Box::new("Could not read output from plugin")))
|
||||||
))),
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
// this forget should be safe because the context will clean up
|
// this forget should be safe because the context will clean up
|
||||||
// all it's plugins when it is dropped
|
// all it's plugins when it is dropped
|
||||||
@@ -99,17 +86,14 @@ fn plugin_call(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rustler::nif]
|
#[rustler::nif]
|
||||||
fn plugin_update_manifest(
|
fn plugin_update_manifest(ctx: ResourceArc<ExtismContext>, plugin_id: i32, manifest_payload: String, wasi: bool) -> Result<(), rustler::Error> {
|
||||||
ctx: ResourceArc<ExtismContext>,
|
|
||||||
plugin_id: i32,
|
|
||||||
manifest_payload: String,
|
|
||||||
wasi: bool,
|
|
||||||
) -> Result<(), rustler::Error> {
|
|
||||||
let context = &ctx.ctx.read().unwrap();
|
let context = &ctx.ctx.read().unwrap();
|
||||||
let mut plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
let mut plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
||||||
let result = match plugin.update(manifest_payload, wasi) {
|
let result = match plugin.update(manifest_payload, wasi) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => {
|
||||||
Err(e) => Err(to_rustler_error(e)),
|
Ok(())
|
||||||
|
},
|
||||||
|
Err(e) => Err(to_rustler_error(e))
|
||||||
};
|
};
|
||||||
// this forget should be safe because the context will clean up
|
// this forget should be safe because the context will clean up
|
||||||
// all it's plugins when it is dropped
|
// all it's plugins when it is dropped
|
||||||
@@ -129,28 +113,19 @@ fn plugin_free(ctx: ResourceArc<ExtismContext>, plugin_id: i32) -> Result<(), ru
|
|||||||
fn set_log_file(filename: String, log_level: String) -> Result<Atom, rustler::Error> {
|
fn set_log_file(filename: String, log_level: String) -> Result<Atom, rustler::Error> {
|
||||||
let path = Path::new(&filename);
|
let path = Path::new(&filename);
|
||||||
match log::Level::from_str(&log_level) {
|
match log::Level::from_str(&log_level) {
|
||||||
Err(_e) => Err(rustler::Error::Term(Box::new(format!(
|
Err(_e) => Err(rustler::Error::Term(Box::new(format!("{} not a valid log level", log_level)))),
|
||||||
"{} not a valid log level",
|
|
||||||
log_level
|
|
||||||
)))),
|
|
||||||
Ok(level) => {
|
Ok(level) => {
|
||||||
if extism::set_log_file(path, Some(level)) {
|
if extism::set_log_file(path, Some(level)) {
|
||||||
Ok(atoms::ok())
|
Ok(atoms::ok())
|
||||||
} else {
|
} else {
|
||||||
Err(rustler::Error::Term(Box::new(
|
Err(rustler::Error::Term(Box::new("Did not set log file, received false from the API.")))
|
||||||
"Did not set log file, received false from the API.",
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustler::nif]
|
#[rustler::nif]
|
||||||
fn plugin_has_function(
|
fn plugin_has_function(ctx: ResourceArc<ExtismContext>, plugin_id: i32, function_name: String) -> Result<bool, rustler::Error> {
|
||||||
ctx: ResourceArc<ExtismContext>,
|
|
||||||
plugin_id: i32,
|
|
||||||
function_name: String,
|
|
||||||
) -> Result<bool, rustler::Error> {
|
|
||||||
let context = &ctx.ctx.read().unwrap();
|
let context = &ctx.ctx.read().unwrap();
|
||||||
let plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
let plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
||||||
let has_function = plugin.has_function(function_name);
|
let has_function = plugin.has_function(function_name);
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
# This file is generated by dune, edit dune-project instead
|
|
||||||
opam-version: "2.0"
|
|
||||||
synopsis: "Extism manifest bindings"
|
|
||||||
description: "Bindings to Extism, the universal plugin system"
|
|
||||||
maintainer: ["Extism Authors <oss@extism.org>"]
|
|
||||||
authors: ["Extism Authors <oss@extism.org>"]
|
|
||||||
license: "BSD-3-Clause"
|
|
||||||
tags: ["topics" "wasm" "plugin"]
|
|
||||||
homepage: "https://github.com/extism/extism"
|
|
||||||
doc: "https://github.com/extism/extism"
|
|
||||||
bug-reports: "https://github.com/extism/extism/issues"
|
|
||||||
depends: [
|
|
||||||
"ocaml" {>= "4.14.1"}
|
|
||||||
"dune" {>= "3.2" & >= "3.2"}
|
|
||||||
"ppx_yojson_conv" {>= "0.15.0"}
|
|
||||||
"base64" {>= "3.5.0"}
|
|
||||||
"odoc" {with-doc}
|
|
||||||
]
|
|
||||||
build: [
|
|
||||||
["dune" "subst"] {dev}
|
|
||||||
[
|
|
||||||
"dune"
|
|
||||||
"build"
|
|
||||||
"-p"
|
|
||||||
name
|
|
||||||
"-j"
|
|
||||||
jobs
|
|
||||||
"@install"
|
|
||||||
"@runtest" {with-test}
|
|
||||||
"@doc" {with-doc}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
dev-repo: "git+https://github.com/extism/extism.git"
|
|
||||||
14
extism.go
14
extism.go
@@ -53,11 +53,11 @@ type WasmFile struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WasmUrl struct {
|
type WasmUrl struct {
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
Hash string `json:"hash,omitempty"`
|
Hash string `json:"hash,omitempty"`
|
||||||
Headers map[string]string `json:"headers,omitempty"`
|
Header map[string]string `json:"header,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Method string `json:"method,omitempty"`
|
Method string `json:"method,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Wasm interface{}
|
type Wasm interface{}
|
||||||
@@ -65,12 +65,10 @@ type Wasm interface{}
|
|||||||
type Manifest struct {
|
type Manifest struct {
|
||||||
Wasm []Wasm `json:"wasm"`
|
Wasm []Wasm `json:"wasm"`
|
||||||
Memory struct {
|
Memory struct {
|
||||||
MaxPages uint32 `json:"max_pages,omitempty"`
|
Max uint32 `json:"max,omitempty"`
|
||||||
} `json:"memory,omitempty"`
|
} `json:"memory,omitempty"`
|
||||||
Config map[string]string `json:"config,omitempty"`
|
Config map[string]string `json:"config,omitempty"`
|
||||||
AllowedHosts []string `json:"allowed_hosts,omitempty"`
|
AllowedHosts []string `json:"allowed_hosts,omitempty"`
|
||||||
AllowedPaths map[string]string `json:"allowed_paths,omitempty"`
|
|
||||||
Timeout uint `json:"timeout_ms,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makePointer(data []byte) unsafe.Pointer {
|
func makePointer(data []byte) unsafe.Pointer {
|
||||||
|
|||||||
15
extism.opam
15
extism.opam
@@ -10,14 +10,13 @@ homepage: "https://github.com/extism/extism"
|
|||||||
doc: "https://github.com/extism/extism"
|
doc: "https://github.com/extism/extism"
|
||||||
bug-reports: "https://github.com/extism/extism/issues"
|
bug-reports: "https://github.com/extism/extism/issues"
|
||||||
depends: [
|
depends: [
|
||||||
"ocaml" {>= "4.14.1"}
|
"ocaml"
|
||||||
"dune" {>= "3.2" & >= "3.2"}
|
"dune" {>= "3.2"}
|
||||||
"ctypes-foreign" {>= "0.18.0"}
|
"ctypes-foreign"
|
||||||
"bigstringaf" {>= "0.9.0"}
|
"bigstringaf"
|
||||||
"ppx_yojson_conv" {>= "0.15.0"}
|
"ppx_yojson_conv"
|
||||||
"extism-manifest"
|
"base64"
|
||||||
"ppx_inline_test" {>= "0.15.0"}
|
"ppx_inline_test"
|
||||||
"cmdliner" {>= "1.1.1"}
|
|
||||||
"odoc" {with-doc}
|
"odoc" {with-doc}
|
||||||
]
|
]
|
||||||
build: [
|
build: [
|
||||||
|
|||||||
@@ -1,16 +1,23 @@
|
|||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
|
import System.Exit (exitFailure, exitSuccess)
|
||||||
|
import qualified Data.ByteString as B
|
||||||
import Extism
|
import Extism
|
||||||
import Extism.Manifest(manifest, wasmFile)
|
import Extism.Manifest
|
||||||
|
|
||||||
unwrap (Right x) = x
|
try f (Right x) = f x
|
||||||
unwrap (Left (ExtismError msg)) = do
|
try f (Left (ErrorMessage msg)) = do
|
||||||
error msg
|
_ <- putStrLn msg
|
||||||
|
exitFailure
|
||||||
|
|
||||||
|
handlePlugin plugin = do
|
||||||
|
res <- Extism.call plugin "count_vowels" (Extism.toByteString "this is a test")
|
||||||
|
try (\bs -> do
|
||||||
|
_ <- putStrLn (Extism.fromByteString bs)
|
||||||
|
_ <- Extism.free plugin
|
||||||
|
exitSuccess) res
|
||||||
|
|
||||||
main = do
|
main = do
|
||||||
let m = manifest [wasmFile "../wasm/code.wasm"]
|
context <- Extism.newContext ()
|
||||||
context <- Extism.newContext
|
plugin <- Extism.pluginFromManifest context (manifest [wasmFile "../wasm/code.wasm"]) False
|
||||||
plugin <- unwrap <$> Extism.pluginFromManifest context m False
|
try handlePlugin plugin
|
||||||
res <- unwrap <$> Extism.call plugin "count_vowels" (Extism.toByteString "this is a test")
|
|
||||||
putStrLn (Extism.fromByteString res)
|
|
||||||
Extism.free plugin
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
.PHONY: test
|
|
||||||
|
|
||||||
prepare:
|
|
||||||
cabal update
|
|
||||||
|
|
||||||
build: prepare
|
|
||||||
cabal build
|
|
||||||
|
|
||||||
test: prepare
|
|
||||||
cabal test
|
|
||||||
|
|
||||||
clean:
|
|
||||||
cabal clean
|
|
||||||
|
|
||||||
publish: clean prepare
|
|
||||||
cabal sdist
|
|
||||||
# TODO: upload
|
|
||||||
|
|
||||||
format:
|
|
||||||
# TODO
|
|
||||||
|
|
||||||
lint:
|
|
||||||
cabal check
|
|
||||||
hlint src manifest
|
|
||||||
|
|
||||||
docs:
|
|
||||||
# TODO
|
|
||||||
|
|
||||||
show-docs: docs
|
|
||||||
# TODO
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
packages: extism.cabal manifest/extism-manifest.cabal
|
|
||||||
@@ -1,45 +1,54 @@
|
|||||||
cabal-version: 3.0
|
cabal-version: 2.4
|
||||||
name: extism
|
name: extism
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
license: BSD-3-Clause
|
|
||||||
maintainer: oss@extism.org
|
-- A short (one-line) description of the package.
|
||||||
|
synopsis: Extism bindings
|
||||||
|
|
||||||
|
-- A longer description of the package.
|
||||||
|
description: Bindings to Extism, the universal plugin system
|
||||||
|
|
||||||
|
-- A URL where users can report bugs.
|
||||||
|
bug-reports: https://github.com/extism/extism
|
||||||
|
|
||||||
|
-- The license under which the package is released.
|
||||||
|
license: BSD-3-Clause
|
||||||
|
|
||||||
author: Extism authors
|
author: Extism authors
|
||||||
bug-reports: https://github.com/extism/extism
|
maintainer: oss@extism.org
|
||||||
synopsis: Extism bindings
|
|
||||||
description: Bindings to Extism, the universal plugin system
|
-- A copyright notice.
|
||||||
category: Plugins, WebAssembly
|
-- copyright:
|
||||||
|
category: Plugins, WebAssembly
|
||||||
extra-source-files: CHANGELOG.md
|
extra-source-files: CHANGELOG.md
|
||||||
|
|
||||||
library
|
library
|
||||||
exposed-modules: Extism
|
exposed-modules: Extism Extism.Manifest
|
||||||
reexported-modules: Extism.Manifest
|
|
||||||
hs-source-dirs: src
|
|
||||||
other-modules: Extism.Bindings
|
|
||||||
default-language: Haskell2010
|
|
||||||
extra-libraries: extism
|
|
||||||
extra-lib-dirs: /usr/local/lib
|
|
||||||
build-depends:
|
|
||||||
base >= 4.16.1 && < 4.18.0,
|
|
||||||
bytestring >= 0.11.3 && < 0.12,
|
|
||||||
json >= 0.10 && < 0.11,
|
|
||||||
extism-manifest >= 0.0.0 && < 0.1.0
|
|
||||||
|
|
||||||
test-suite extism-example
|
-- Modules included in this library but not exported.
|
||||||
type: exitcode-stdio-1.0
|
other-modules:
|
||||||
main-is: Example.hs
|
|
||||||
|
-- LANGUAGE extensions used by modules in this package.
|
||||||
|
-- other-extensions:
|
||||||
|
build-depends:
|
||||||
|
base ^>=4.16.1.0
|
||||||
|
, bytestring
|
||||||
|
, base64-bytestring
|
||||||
|
, json
|
||||||
|
hs-source-dirs: src
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
build-depends:
|
extra-libraries: extism
|
||||||
base,
|
extra-lib-dirs: /usr/local/lib
|
||||||
extism,
|
|
||||||
bytestring
|
Test-Suite extism-example
|
||||||
|
type: exitcode-stdio-1.0
|
||||||
test-suite extism-test
|
main-is: Example.hs
|
||||||
type: exitcode-stdio-1.0
|
build-depends: base, extism, bytestring
|
||||||
main-is: Test.hs
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
Test-Suite extism-test
|
||||||
|
type: exitcode-stdio-1.0
|
||||||
|
main-is: Test.hs
|
||||||
hs-source-dirs: test
|
hs-source-dirs: test
|
||||||
|
build-depends: base, extism, bytestring, HUnit
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
build-depends:
|
|
||||||
base,
|
|
||||||
extism,
|
|
||||||
bytestring,
|
|
||||||
HUnit
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
# Revision history for extism-manifest
|
|
||||||
|
|
||||||
## 0.1.0.0 -- YYYY-mm-dd
|
|
||||||
|
|
||||||
* First version. Released on an unsuspecting world.
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
module Extism.JSON (
|
|
||||||
module Extism.JSON,
|
|
||||||
module Text.JSON
|
|
||||||
) where
|
|
||||||
|
|
||||||
import Text.JSON
|
|
||||||
import qualified Data.ByteString as B
|
|
||||||
import Data.ByteString.Internal (c2w, w2c)
|
|
||||||
import qualified Data.ByteString.Base64 as B64
|
|
||||||
import qualified Data.ByteString.Char8 as BS (unpack)
|
|
||||||
|
|
||||||
data Nullable a = Null | NotNull a
|
|
||||||
|
|
||||||
makeArray x = JSArray [showJSON a | a <- x]
|
|
||||||
isNull JSNull = True
|
|
||||||
isNull _ = False
|
|
||||||
filterNulls obj = [(a, b) | (a, b) <- obj, not (isNull b)]
|
|
||||||
object x = makeObj $ filterNulls x
|
|
||||||
objectWithNulls x = makeObj x
|
|
||||||
nonNull x = NotNull x
|
|
||||||
null' = Null
|
|
||||||
(.=) a b = (a, showJSON b)
|
|
||||||
toNullable (Just x) = NotNull x
|
|
||||||
toNullable Nothing = Null
|
|
||||||
fromNullable (NotNull x) = Just x
|
|
||||||
fromNullable Null = Nothing
|
|
||||||
mapNullable f Null = Null
|
|
||||||
mapNullable f (NotNull x) = NotNull (f x)
|
|
||||||
|
|
||||||
(.?) (JSObject a) k =
|
|
||||||
case valFromObj k a of
|
|
||||||
Ok x -> NotNull x
|
|
||||||
Error _ -> Null
|
|
||||||
(.?) _ _ = Null
|
|
||||||
(.??) a k = toNullable $ lookup k a
|
|
||||||
|
|
||||||
find :: JSON a => String -> JSValue -> Nullable a
|
|
||||||
find k obj = obj .? k
|
|
||||||
|
|
||||||
update :: JSON a => String -> a -> JSValue -> JSValue
|
|
||||||
update k v (JSObject obj) = object $ (fromJSObject obj) ++ [k .= v]
|
|
||||||
|
|
||||||
instance JSON a => JSON (Nullable a) where
|
|
||||||
showJSON (NotNull x) = showJSON x
|
|
||||||
showJSON Null = JSNull
|
|
||||||
readJSON JSNull = Ok Null
|
|
||||||
readJSON x = readJSON x
|
|
||||||
|
|
||||||
|
|
||||||
newtype Base64 = Base64 B.ByteString
|
|
||||||
|
|
||||||
instance JSON Base64 where
|
|
||||||
showJSON (Base64 bs) = showJSON (BS.unpack $ B64.encode bs)
|
|
||||||
readJSON (JSString s) =
|
|
||||||
let toByteString x = B.pack (Prelude.map c2w x) in
|
|
||||||
case B64.decode (toByteString (fromJSString s)) of
|
|
||||||
Left msg -> Error msg
|
|
||||||
Right d -> Ok (Base64 d)
|
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
module Extism.Manifest where
|
|
||||||
|
|
||||||
import Extism.JSON
|
|
||||||
import qualified Data.ByteString as B
|
|
||||||
import qualified Data.ByteString.Char8 as BS (unpack)
|
|
||||||
|
|
||||||
-- | Memory options
|
|
||||||
newtype Memory = Memory
|
|
||||||
{
|
|
||||||
memoryMaxPages :: Nullable Int
|
|
||||||
}
|
|
||||||
|
|
||||||
instance JSON Memory where
|
|
||||||
showJSON (Memory max) =
|
|
||||||
object [
|
|
||||||
"max_pages" .= max
|
|
||||||
]
|
|
||||||
readJSON obj =
|
|
||||||
let max = obj .? "max_pages" in
|
|
||||||
Ok (Memory max)
|
|
||||||
|
|
||||||
-- | HTTP request
|
|
||||||
data HTTPRequest = HTTPRequest
|
|
||||||
{
|
|
||||||
url :: String
|
|
||||||
, headers :: Nullable [(String, String)]
|
|
||||||
, method :: Nullable String
|
|
||||||
}
|
|
||||||
|
|
||||||
makeKV x =
|
|
||||||
object [(k, showJSON v) | (k, v) <- x]
|
|
||||||
|
|
||||||
requestObj (HTTPRequest url headers method) =
|
|
||||||
[
|
|
||||||
"url" .= url,
|
|
||||||
"headers" .= mapNullable makeKV headers,
|
|
||||||
"method" .= method
|
|
||||||
]
|
|
||||||
|
|
||||||
instance JSON HTTPRequest where
|
|
||||||
showJSON req = object $ requestObj req
|
|
||||||
readJSON x =
|
|
||||||
let url = x .? "url" in
|
|
||||||
let headers = x .? "headers" in
|
|
||||||
let method = x .? "method" in
|
|
||||||
case url of
|
|
||||||
Null -> Error "Missing 'url' field"
|
|
||||||
NotNull url -> Ok (HTTPRequest url headers method)
|
|
||||||
|
|
||||||
|
|
||||||
-- | WASM from file
|
|
||||||
data WasmFile = WasmFile
|
|
||||||
{
|
|
||||||
filePath :: String
|
|
||||||
, fileName :: Nullable String
|
|
||||||
, fileHash :: Nullable String
|
|
||||||
}
|
|
||||||
|
|
||||||
instance JSON WasmFile where
|
|
||||||
showJSON (WasmFile path name hash) =
|
|
||||||
object [
|
|
||||||
"path" .= path,
|
|
||||||
"name" .= name,
|
|
||||||
"hash" .= hash
|
|
||||||
]
|
|
||||||
readJSON x =
|
|
||||||
let path = x .? "url" in
|
|
||||||
let name = x .? "name" in
|
|
||||||
let hash = x .? "hash" in
|
|
||||||
case path of
|
|
||||||
Null -> Error "Missing 'path' field"
|
|
||||||
NotNull path -> Ok (WasmFile path name hash)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- | WASM from raw bytes
|
|
||||||
data WasmData = WasmData
|
|
||||||
{
|
|
||||||
dataBytes :: Base64
|
|
||||||
, dataName :: Nullable String
|
|
||||||
, dataHash :: Nullable String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
instance JSON WasmData where
|
|
||||||
showJSON (WasmData bytes name hash) =
|
|
||||||
object [
|
|
||||||
"data" .= bytes,
|
|
||||||
"name" .= name,
|
|
||||||
"hash" .= hash
|
|
||||||
]
|
|
||||||
readJSON x =
|
|
||||||
let d = x .? "data" in
|
|
||||||
let name = x .? "name" in
|
|
||||||
let hash = x .? "hash" in
|
|
||||||
case d of
|
|
||||||
Null -> Error "Missing 'path' field"
|
|
||||||
NotNull d ->
|
|
||||||
case readJSON d of
|
|
||||||
Error msg -> Error msg
|
|
||||||
Ok d' -> Ok (WasmData d' name hash)
|
|
||||||
|
|
||||||
|
|
||||||
-- | WASM from a URL
|
|
||||||
data WasmURL = WasmURL
|
|
||||||
{
|
|
||||||
req :: HTTPRequest
|
|
||||||
, urlName :: Nullable String
|
|
||||||
, urlHash :: Nullable String
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
instance JSON WasmURL where
|
|
||||||
showJSON (WasmURL req name hash) =
|
|
||||||
object (
|
|
||||||
"name" .= name :
|
|
||||||
"hash" .= hash :
|
|
||||||
requestObj req)
|
|
||||||
readJSON x =
|
|
||||||
let req = x .? "req" in
|
|
||||||
let name = x .? "name" in
|
|
||||||
let hash = x .? "hash" in
|
|
||||||
case fromNullable req of
|
|
||||||
Nothing -> Error "Missing 'req' field"
|
|
||||||
Just req -> Ok (WasmURL req name hash)
|
|
||||||
|
|
||||||
-- | Specifies where to get WASM module data
|
|
||||||
data Wasm = File WasmFile | Data WasmData | URL WasmURL
|
|
||||||
|
|
||||||
instance JSON Wasm where
|
|
||||||
showJSON x =
|
|
||||||
case x of
|
|
||||||
File f -> showJSON f
|
|
||||||
Data d -> showJSON d
|
|
||||||
URL u -> showJSON u
|
|
||||||
readJSON x =
|
|
||||||
let file = (readJSON x :: Result WasmFile) in
|
|
||||||
case file of
|
|
||||||
Ok x -> Ok (File x)
|
|
||||||
Error _ ->
|
|
||||||
let data' = (readJSON x :: Result WasmData) in
|
|
||||||
case data' of
|
|
||||||
Ok x -> Ok (Data x)
|
|
||||||
Error _ ->
|
|
||||||
let url = (readJSON x :: Result WasmURL) in
|
|
||||||
case url of
|
|
||||||
Ok x -> Ok (URL x)
|
|
||||||
Error _ -> Error "JSON does not match any of the Wasm types"
|
|
||||||
|
|
||||||
wasmFile :: String -> Wasm
|
|
||||||
wasmFile path =
|
|
||||||
File WasmFile { filePath = path, fileName = null', fileHash = null'}
|
|
||||||
|
|
||||||
wasmURL :: String -> String -> Wasm
|
|
||||||
wasmURL method url =
|
|
||||||
let r = HTTPRequest { url = url, headers = null', method = nonNull method } in
|
|
||||||
URL WasmURL { req = r, urlName = null', urlHash = null' }
|
|
||||||
|
|
||||||
wasmData :: B.ByteString -> Wasm
|
|
||||||
wasmData d =
|
|
||||||
Data WasmData { dataBytes = Base64 d, dataName = null', dataHash = null' }
|
|
||||||
|
|
||||||
withName :: Wasm -> String -> Wasm
|
|
||||||
withName (Data d) name = Data d { dataName = nonNull name }
|
|
||||||
withName (URL url) name = URL url { urlName = nonNull name }
|
|
||||||
withName (File f) name = File f { fileName = nonNull name }
|
|
||||||
|
|
||||||
|
|
||||||
withHash :: Wasm -> String -> Wasm
|
|
||||||
withHash (Data d) hash = Data d { dataHash = nonNull hash }
|
|
||||||
withHash (URL url) hash = URL url { urlHash = nonNull hash }
|
|
||||||
withHash (File f) hash = File f { fileHash = nonNull hash }
|
|
||||||
|
|
||||||
-- | The 'Manifest' type is used to provide WASM data and configuration to the
|
|
||||||
-- | Extism runtime
|
|
||||||
data Manifest = Manifest
|
|
||||||
{
|
|
||||||
wasm :: [Wasm]
|
|
||||||
, memory :: Nullable Memory
|
|
||||||
, config :: Nullable [(String, String)]
|
|
||||||
, allowedHosts :: Nullable [String]
|
|
||||||
, allowedPaths :: Nullable [(String, String)]
|
|
||||||
, timeout :: Nullable Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
instance JSON Manifest where
|
|
||||||
showJSON (Manifest wasm memory config hosts paths timeout) =
|
|
||||||
let w = makeArray wasm in
|
|
||||||
object [
|
|
||||||
"wasm" .= w,
|
|
||||||
"memory" .= memory,
|
|
||||||
"config" .= mapNullable makeKV config,
|
|
||||||
"allowed_hosts" .= hosts,
|
|
||||||
"allowed_paths" .= mapNullable makeKV paths,
|
|
||||||
"timeout_ms" .= timeout
|
|
||||||
]
|
|
||||||
readJSON x =
|
|
||||||
let wasm = x .? "wasm" in
|
|
||||||
let memory = x .? "memory" in
|
|
||||||
let config = x .? "config" in
|
|
||||||
let hosts = x .? "allowed_hosts" in
|
|
||||||
let paths = x .? "allowed_paths" in
|
|
||||||
let timeout = x .? "timeout_ms" in
|
|
||||||
case fromNullable wasm of
|
|
||||||
Nothing -> Error "Missing 'wasm' field"
|
|
||||||
Just wasm -> Ok (Manifest wasm memory config hosts paths timeout)
|
|
||||||
|
|
||||||
-- | Create a new 'Manifest' from a list of 'Wasm'
|
|
||||||
manifest :: [Wasm] -> Manifest
|
|
||||||
manifest wasm =
|
|
||||||
Manifest {
|
|
||||||
wasm = wasm,
|
|
||||||
memory = null',
|
|
||||||
config = null',
|
|
||||||
allowedHosts = null',
|
|
||||||
allowedPaths = null',
|
|
||||||
timeout = null'
|
|
||||||
}
|
|
||||||
|
|
||||||
-- | Update the config values
|
|
||||||
withConfig :: Manifest -> [(String, String)] -> Manifest
|
|
||||||
withConfig m config =
|
|
||||||
m { config = nonNull config }
|
|
||||||
|
|
||||||
|
|
||||||
-- | Update allowed hosts for `extism_http_request`
|
|
||||||
withHosts :: Manifest -> [String] -> Manifest
|
|
||||||
withHosts m hosts =
|
|
||||||
m { allowedHosts = nonNull hosts }
|
|
||||||
|
|
||||||
|
|
||||||
-- | Update allowed paths
|
|
||||||
withPaths :: Manifest -> [(String, String)] -> Manifest
|
|
||||||
withPaths m p =
|
|
||||||
m { allowedPaths = nonNull p }
|
|
||||||
|
|
||||||
-- | Update plugin timeout (in milliseconds)
|
|
||||||
withTimeout :: Manifest -> Int -> Manifest
|
|
||||||
withTimeout m t =
|
|
||||||
m { timeout = nonNull t }
|
|
||||||
|
|
||||||
toString :: (JSON a) => a -> String
|
|
||||||
toString v =
|
|
||||||
encode (showJSON v)
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
cabal-version: 3.0
|
|
||||||
name: extism-manifest
|
|
||||||
version: 0.0.1
|
|
||||||
license: BSD-3-Clause
|
|
||||||
maintainer: oss@extism.org
|
|
||||||
author: Extism authors
|
|
||||||
bug-reports: https://github.com/extism/extism
|
|
||||||
synopsis: Extism manifest bindings
|
|
||||||
description: Bindings to Extism WebAssembly manifest
|
|
||||||
category: Plugins, WebAssembly
|
|
||||||
extra-source-files: CHANGELOG.md
|
|
||||||
|
|
||||||
library
|
|
||||||
exposed-modules: Extism.Manifest Extism.JSON
|
|
||||||
hs-source-dirs: .
|
|
||||||
default-language: Haskell2010
|
|
||||||
build-depends:
|
|
||||||
base >= 4.16.1 && < 4.18.0,
|
|
||||||
bytestring >= 0.11.3 && < 0.12,
|
|
||||||
json >= 0.10 && < 0.11,
|
|
||||||
base64-bytestring >= 1.2.1 && < 1.3,
|
|
||||||
@@ -1,68 +1,84 @@
|
|||||||
|
{-# LANGUAGE ForeignFunctionInterface #-}
|
||||||
|
|
||||||
module Extism (module Extism, module Extism.Manifest) where
|
module Extism (module Extism, module Extism.Manifest) where
|
||||||
import Data.Int
|
import GHC.Int
|
||||||
import Data.Word
|
import GHC.Word
|
||||||
import Control.Monad (void)
|
import Foreign.C.Types
|
||||||
|
import Foreign.Ptr
|
||||||
import Foreign.ForeignPtr
|
import Foreign.ForeignPtr
|
||||||
import Foreign.C.String
|
import Foreign.C.String
|
||||||
import Foreign.Ptr
|
import Control.Monad (void)
|
||||||
import Data.ByteString as B
|
import Data.ByteString as B
|
||||||
import Data.ByteString.Internal (c2w, w2c)
|
import Data.ByteString.Internal (c2w, w2c)
|
||||||
import Data.ByteString.Unsafe (unsafeUseAsCString)
|
import Data.ByteString.Unsafe (unsafeUseAsCString)
|
||||||
import Data.Bifunctor (second)
|
import Data.Bifunctor (second)
|
||||||
import Text.JSON (encode, toJSObject, showJSON)
|
import Text.JSON (JSON, toJSObject, toJSString, encode, JSValue(JSNull, JSString))
|
||||||
import Extism.Manifest (Manifest, toString)
|
import Extism.Manifest (Manifest, toString)
|
||||||
import Extism.Bindings
|
|
||||||
|
|
||||||
-- | Context for managing plugins
|
newtype ExtismContext = ExtismContext () deriving Show
|
||||||
|
|
||||||
|
foreign import ccall unsafe "extism.h extism_context_new" extism_context_new :: IO (Ptr ExtismContext)
|
||||||
|
foreign import ccall unsafe "extism.h &extism_context_free" extism_context_free :: FunPtr (Ptr ExtismContext -> IO ())
|
||||||
|
foreign import ccall unsafe "extism.h extism_plugin_new" extism_plugin_new :: Ptr ExtismContext -> Ptr Word8 -> Word64 -> CBool -> IO Int32
|
||||||
|
foreign import ccall unsafe "extism.h extism_plugin_update" extism_plugin_update :: Ptr ExtismContext -> Int32 -> Ptr Word8 -> Word64 -> CBool -> IO CBool
|
||||||
|
foreign import ccall unsafe "extism.h extism_plugin_call" extism_plugin_call :: Ptr ExtismContext -> Int32 -> CString -> Ptr Word8 -> Word64 -> IO Int32
|
||||||
|
foreign import ccall unsafe "extism.h extism_plugin_function_exists" extism_plugin_function_exists :: Ptr ExtismContext -> Int32 -> CString -> IO CBool
|
||||||
|
foreign import ccall unsafe "extism.h extism_error" extism_error :: Ptr ExtismContext -> Int32 -> IO CString
|
||||||
|
foreign import ccall unsafe "extism.h extism_plugin_output_length" extism_plugin_output_length :: Ptr ExtismContext -> Int32 -> IO Word64
|
||||||
|
foreign import ccall unsafe "extism.h extism_plugin_output_data" extism_plugin_output_data :: Ptr ExtismContext -> Int32 -> IO (Ptr Word8)
|
||||||
|
foreign import ccall unsafe "extism.h extism_log_file" extism_log_file :: CString -> CString -> IO CBool
|
||||||
|
foreign import ccall unsafe "extism.h extism_plugin_config" extism_plugin_config :: Ptr ExtismContext -> Int32 -> Ptr Word8 -> Int64 -> IO CBool
|
||||||
|
foreign import ccall unsafe "extism.h extism_plugin_free" extism_plugin_free :: Ptr ExtismContext -> Int32 -> IO ()
|
||||||
|
foreign import ccall unsafe "extism.h extism_context_reset" extism_context_reset :: Ptr ExtismContext -> IO ()
|
||||||
|
foreign import ccall unsafe "extism.h extism_version" extism_version :: IO CString
|
||||||
|
|
||||||
|
-- Context manages plugins
|
||||||
newtype Context = Context (ForeignPtr ExtismContext)
|
newtype Context = Context (ForeignPtr ExtismContext)
|
||||||
|
|
||||||
-- | Plugins can be used to call WASM function
|
-- Plugins can be used to call WASM function
|
||||||
data Plugin = Plugin Context Int32
|
data Plugin = Plugin Context Int32
|
||||||
|
|
||||||
-- | Log level
|
-- Log level
|
||||||
data LogLevel = Error | Warn | Info | Debug | Trace deriving (Show)
|
data LogLevel = Error | Warn | Info | Debug | Trace deriving (Show)
|
||||||
|
|
||||||
-- | Extism error
|
-- Extism error
|
||||||
newtype Error = ExtismError String deriving Show
|
newtype Error = ErrorMessage String deriving Show
|
||||||
|
|
||||||
-- | Result type
|
-- Helper function to convert a string to a bytestring
|
||||||
type Result a = Either Error a
|
|
||||||
|
|
||||||
-- | Helper function to convert a 'String' to a 'ByteString'
|
|
||||||
toByteString :: String -> ByteString
|
toByteString :: String -> ByteString
|
||||||
toByteString x = B.pack (Prelude.map c2w x)
|
toByteString x = B.pack (Prelude.map c2w x)
|
||||||
|
|
||||||
-- | Helper function to convert a 'ByteString' to a 'String'
|
-- Helper function to convert a bytestring to a string
|
||||||
fromByteString :: ByteString -> String
|
fromByteString :: ByteString -> String
|
||||||
fromByteString bs = Prelude.map w2c $ B.unpack bs
|
fromByteString bs = Prelude.map w2c $ B.unpack bs
|
||||||
|
|
||||||
-- | Get the Extism version string
|
-- Get the Extism version string
|
||||||
extismVersion :: () -> IO String
|
extismVersion :: () -> IO String
|
||||||
extismVersion () = do
|
extismVersion () = do
|
||||||
v <- extism_version
|
v <- extism_version
|
||||||
peekCString v
|
peekCString v
|
||||||
|
|
||||||
-- | Remove all registered plugins in a 'Context'
|
-- Remove all registered plugins in a Context
|
||||||
reset :: Context -> IO ()
|
reset :: Context -> IO ()
|
||||||
reset (Context ctx) =
|
reset (Context ctx) =
|
||||||
withForeignPtr ctx extism_context_reset
|
withForeignPtr ctx extism_context_reset
|
||||||
|
|
||||||
-- | Create a new 'Context'
|
-- Create a new context
|
||||||
newContext :: IO Context
|
newContext :: () -> IO Context
|
||||||
newContext = do
|
newContext () = do
|
||||||
ptr <- extism_context_new
|
ptr <- extism_context_new
|
||||||
fptr <- newForeignPtr extism_context_free ptr
|
fptr <- newForeignPtr extism_context_free ptr
|
||||||
return (Context fptr)
|
return (Context fptr)
|
||||||
|
|
||||||
-- | Execute a function with a new 'Context' that is destroyed when it returns
|
-- Execute a function with a new context that is destroyed when it returns
|
||||||
withContext :: (Context -> IO a) -> IO a
|
withContext :: (Context -> IO a) -> IO a
|
||||||
withContext f = do
|
withContext f = do
|
||||||
ctx <- newContext
|
ctx <- newContext ()
|
||||||
f ctx
|
f ctx
|
||||||
|
|
||||||
-- | Create a 'Plugin' from a WASM module, `useWasi` determines if WASI should
|
-- Create a plugin from a WASM module, `useWasi` determines if WASI should
|
||||||
-- | be linked
|
-- be linked
|
||||||
plugin :: Context -> B.ByteString -> Bool -> IO (Result Plugin)
|
plugin :: Context -> B.ByteString -> Bool -> IO (Either Error Plugin)
|
||||||
plugin c wasm useWasi =
|
plugin c wasm useWasi =
|
||||||
let length = fromIntegral (B.length wasm) in
|
let length = fromIntegral (B.length wasm) in
|
||||||
let wasi = fromInteger (if useWasi then 1 else 0) in
|
let wasi = fromInteger (if useWasi then 1 else 0) in
|
||||||
@@ -74,18 +90,18 @@ plugin c wasm useWasi =
|
|||||||
if p < 0 then do
|
if p < 0 then do
|
||||||
err <- extism_error ctx (-1)
|
err <- extism_error ctx (-1)
|
||||||
e <- peekCString err
|
e <- peekCString err
|
||||||
return $ Left (ExtismError e)
|
return $ Left (ErrorMessage e)
|
||||||
else
|
else
|
||||||
return $ Right (Plugin c p))
|
return $ Right (Plugin c p))
|
||||||
|
|
||||||
-- | Create a 'Plugin' from a 'Manifest'
|
-- Create a plugin from a Manifest
|
||||||
pluginFromManifest :: Context -> Manifest -> Bool -> IO (Result Plugin)
|
pluginFromManifest :: Context -> Manifest -> Bool -> IO (Either Error Plugin)
|
||||||
pluginFromManifest ctx manifest useWasi =
|
pluginFromManifest ctx manifest useWasi =
|
||||||
let wasm = toByteString $ toString manifest in
|
let wasm = toByteString $ toString manifest in
|
||||||
plugin ctx wasm useWasi
|
plugin ctx wasm useWasi
|
||||||
|
|
||||||
-- | Update a 'Plugin' with a new WASM module
|
-- Update a plugin with a new WASM module
|
||||||
update :: Plugin -> B.ByteString -> Bool -> IO (Result ())
|
update :: Plugin -> B.ByteString -> Bool -> IO (Either Error ())
|
||||||
update (Plugin (Context ctx) id) wasm useWasi =
|
update (Plugin (Context ctx) id) wasm useWasi =
|
||||||
let length = fromIntegral (B.length wasm) in
|
let length = fromIntegral (B.length wasm) in
|
||||||
let wasi = fromInteger (if useWasi then 1 else 0) in
|
let wasi = fromInteger (if useWasi then 1 else 0) in
|
||||||
@@ -96,27 +112,30 @@ update (Plugin (Context ctx) id) wasm useWasi =
|
|||||||
if b <= 0 then do
|
if b <= 0 then do
|
||||||
err <- extism_error ctx (-1)
|
err <- extism_error ctx (-1)
|
||||||
e <- peekCString err
|
e <- peekCString err
|
||||||
return $ Left (ExtismError e)
|
return $ Left (ErrorMessage e)
|
||||||
else
|
else
|
||||||
return (Right ()))
|
return (Right ()))
|
||||||
|
|
||||||
-- | Update a 'Plugin' with a new 'Manifest'
|
-- Update a plugin with a new Manifest
|
||||||
updateManifest :: Plugin -> Manifest -> Bool -> IO (Result ())
|
updateManifest :: Plugin -> Manifest -> Bool -> IO (Either Error ())
|
||||||
updateManifest plugin manifest useWasi =
|
updateManifest plugin manifest useWasi =
|
||||||
let wasm = toByteString $ toString manifest in
|
let wasm = toByteString $ toString manifest in
|
||||||
update plugin wasm useWasi
|
update plugin wasm useWasi
|
||||||
|
|
||||||
-- | Check if a 'Plugin' is valid
|
-- Check if a plugin is value
|
||||||
isValid :: Plugin -> Bool
|
isValid :: Plugin -> Bool
|
||||||
isValid (Plugin _ p) = p >= 0
|
isValid (Plugin _ p) = p >= 0
|
||||||
|
|
||||||
-- | Set configuration values for a plugin
|
convertMaybeString Nothing = JSNull
|
||||||
|
convertMaybeString (Just s) = JSString (toJSString s)
|
||||||
|
|
||||||
|
-- Set configuration values for a plugin
|
||||||
setConfig :: Plugin -> [(String, Maybe String)] -> IO Bool
|
setConfig :: Plugin -> [(String, Maybe String)] -> IO Bool
|
||||||
setConfig (Plugin (Context ctx) plugin) x =
|
setConfig (Plugin (Context ctx) plugin) x =
|
||||||
if plugin < 0
|
if plugin < 0
|
||||||
then return False
|
then return False
|
||||||
else
|
else
|
||||||
let obj = toJSObject [(k, showJSON v) | (k, v) <- x] in
|
let obj = toJSObject [(k, convertMaybeString v) | (k, v) <- x] in
|
||||||
let bs = toByteString (encode obj) in
|
let bs = toByteString (encode obj) in
|
||||||
let length = fromIntegral (B.length bs) in
|
let length = fromIntegral (B.length bs) in
|
||||||
unsafeUseAsCString bs (\s -> do
|
unsafeUseAsCString bs (\s -> do
|
||||||
@@ -130,7 +149,7 @@ levelStr Warn = "warn"
|
|||||||
levelStr Trace = "trace"
|
levelStr Trace = "trace"
|
||||||
levelStr Info = "info"
|
levelStr Info = "info"
|
||||||
|
|
||||||
-- | Set the log file and level, this is a global configuration
|
-- Set the log file and level, this is a global configuration
|
||||||
setLogFile :: String -> LogLevel -> IO Bool
|
setLogFile :: String -> LogLevel -> IO Bool
|
||||||
setLogFile filename level =
|
setLogFile filename level =
|
||||||
let s = levelStr level in
|
let s = levelStr level in
|
||||||
@@ -139,15 +158,15 @@ setLogFile filename level =
|
|||||||
b <- extism_log_file f l
|
b <- extism_log_file f l
|
||||||
return $ b /= 0))
|
return $ b /= 0))
|
||||||
|
|
||||||
-- | Check if a function exists in the given plugin
|
-- Check if a function exists in the given plugin
|
||||||
functionExists :: Plugin -> String -> IO Bool
|
functionExists :: Plugin -> String -> IO Bool
|
||||||
functionExists (Plugin (Context ctx) plugin) name = do
|
functionExists (Plugin (Context ctx) plugin) name = do
|
||||||
withForeignPtr ctx (\ctx -> do
|
withForeignPtr ctx (\ctx -> do
|
||||||
b <- withCString name (extism_plugin_function_exists ctx plugin)
|
b <- withCString name (extism_plugin_function_exists ctx plugin)
|
||||||
if b == 1 then return True else return False)
|
if b == 1 then return True else return False)
|
||||||
|
|
||||||
--- | Call a function provided by the given plugin
|
--- Call a function provided by the given plugin
|
||||||
call :: Plugin -> String -> B.ByteString -> IO (Result B.ByteString)
|
call :: Plugin -> String -> B.ByteString -> IO (Either Error B.ByteString)
|
||||||
call (Plugin (Context ctx) plugin) name input =
|
call (Plugin (Context ctx) plugin) name input =
|
||||||
let length = fromIntegral (B.length input) in
|
let length = fromIntegral (B.length input) in
|
||||||
do
|
do
|
||||||
@@ -158,17 +177,16 @@ call (Plugin (Context ctx) plugin) name input =
|
|||||||
err <- extism_error ctx plugin
|
err <- extism_error ctx plugin
|
||||||
if err /= nullPtr
|
if err /= nullPtr
|
||||||
then do e <- peekCString err
|
then do e <- peekCString err
|
||||||
return $ Left (ExtismError e)
|
return $ Left (ErrorMessage e)
|
||||||
else if rc == 0
|
else if rc == 0
|
||||||
then do
|
then do
|
||||||
length <- extism_plugin_output_length ctx plugin
|
length <- extism_plugin_output_length ctx plugin
|
||||||
ptr <- extism_plugin_output_data ctx plugin
|
ptr <- extism_plugin_output_data ctx plugin
|
||||||
buf <- packCStringLen (castPtr ptr, fromIntegral length)
|
buf <- packCStringLen (castPtr ptr, fromIntegral length)
|
||||||
return $ Right buf
|
return $ Right buf
|
||||||
else return $ Left (ExtismError "Call failed"))
|
else return $ Left (ErrorMessage "Call failed"))
|
||||||
|
|
||||||
-- | Free a 'Plugin', this will automatically be called for every plugin
|
-- Free a plugin
|
||||||
-- | associated with a 'Context' when that 'Context' is freed
|
|
||||||
free :: Plugin -> IO ()
|
free :: Plugin -> IO ()
|
||||||
free (Plugin (Context ctx) plugin) =
|
free (Plugin (Context ctx) plugin) =
|
||||||
withForeignPtr ctx (`extism_plugin_free` plugin)
|
withForeignPtr ctx (`extism_plugin_free` plugin)
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
{-# LANGUAGE ForeignFunctionInterface #-}
|
|
||||||
|
|
||||||
module Extism.Bindings where
|
|
||||||
|
|
||||||
import Foreign.C.Types
|
|
||||||
import Foreign.Ptr
|
|
||||||
import Foreign.C.String
|
|
||||||
import Data.Int
|
|
||||||
import Data.Word
|
|
||||||
|
|
||||||
newtype ExtismContext = ExtismContext () deriving Show
|
|
||||||
|
|
||||||
foreign import ccall unsafe "extism.h extism_context_new" extism_context_new :: IO (Ptr ExtismContext)
|
|
||||||
foreign import ccall unsafe "extism.h &extism_context_free" extism_context_free :: FunPtr (Ptr ExtismContext -> IO ())
|
|
||||||
foreign import ccall unsafe "extism.h extism_plugin_new" extism_plugin_new :: Ptr ExtismContext -> Ptr Word8 -> Word64 -> CBool -> IO Int32
|
|
||||||
foreign import ccall unsafe "extism.h extism_plugin_update" extism_plugin_update :: Ptr ExtismContext -> Int32 -> Ptr Word8 -> Word64 -> CBool -> IO CBool
|
|
||||||
foreign import ccall unsafe "extism.h extism_plugin_call" extism_plugin_call :: Ptr ExtismContext -> Int32 -> CString -> Ptr Word8 -> Word64 -> IO Int32
|
|
||||||
foreign import ccall unsafe "extism.h extism_plugin_function_exists" extism_plugin_function_exists :: Ptr ExtismContext -> Int32 -> CString -> IO CBool
|
|
||||||
foreign import ccall unsafe "extism.h extism_error" extism_error :: Ptr ExtismContext -> Int32 -> IO CString
|
|
||||||
foreign import ccall unsafe "extism.h extism_plugin_output_length" extism_plugin_output_length :: Ptr ExtismContext -> Int32 -> IO Word64
|
|
||||||
foreign import ccall unsafe "extism.h extism_plugin_output_data" extism_plugin_output_data :: Ptr ExtismContext -> Int32 -> IO (Ptr Word8)
|
|
||||||
foreign import ccall unsafe "extism.h extism_log_file" extism_log_file :: CString -> CString -> IO CBool
|
|
||||||
foreign import ccall unsafe "extism.h extism_plugin_config" extism_plugin_config :: Ptr ExtismContext -> Int32 -> Ptr Word8 -> Int64 -> IO CBool
|
|
||||||
foreign import ccall unsafe "extism.h extism_plugin_free" extism_plugin_free :: Ptr ExtismContext -> Int32 -> IO ()
|
|
||||||
foreign import ccall unsafe "extism.h extism_context_reset" extism_context_reset :: Ptr ExtismContext -> IO ()
|
|
||||||
foreign import ccall unsafe "extism.h extism_version" extism_version :: IO CString
|
|
||||||
183
haskell/src/Extism/Manifest.hs
Normal file
183
haskell/src/Extism/Manifest.hs
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
module Extism.Manifest where
|
||||||
|
|
||||||
|
import Text.JSON
|
||||||
|
(
|
||||||
|
JSValue(JSNull, JSString, JSArray),
|
||||||
|
toJSString, showJSON, makeObj, encode
|
||||||
|
)
|
||||||
|
import qualified Data.ByteString as B
|
||||||
|
import qualified Data.ByteString.Base64 as B64
|
||||||
|
import qualified Data.ByteString.Char8 as BS (unpack)
|
||||||
|
|
||||||
|
valueOrNull f Nothing = JSNull
|
||||||
|
valueOrNull f (Just x) = f x
|
||||||
|
makeString s = JSString (toJSString s)
|
||||||
|
stringOrNull = valueOrNull makeString
|
||||||
|
makeArray f [] = JSNull
|
||||||
|
makeArray f x = JSArray [f a | a <- x]
|
||||||
|
filterNulls obj = [(a, b) | (a, b) <- obj, not (isNull b)]
|
||||||
|
mapObj f x = makeObj (filterNulls [(a, f b) | (a, b) <- x])
|
||||||
|
isNull JSNull = True
|
||||||
|
isNull _ = False
|
||||||
|
|
||||||
|
newtype Memory = Memory
|
||||||
|
{
|
||||||
|
memoryMax :: Maybe Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class JSONValue a where
|
||||||
|
toJSONValue :: a -> JSValue
|
||||||
|
|
||||||
|
instance JSONValue Memory where
|
||||||
|
toJSONValue x =
|
||||||
|
case memoryMax x of
|
||||||
|
Nothing -> makeObj []
|
||||||
|
Just max -> makeObj [("max", showJSON max)]
|
||||||
|
|
||||||
|
data HttpRequest = HttpRequest
|
||||||
|
{
|
||||||
|
url :: String
|
||||||
|
, header :: [(String, String)]
|
||||||
|
, method :: Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
requestObj x =
|
||||||
|
let meth = stringOrNull $ method x in
|
||||||
|
let h = mapObj makeString $ header x in
|
||||||
|
filterNulls [
|
||||||
|
("url", makeString $ url x),
|
||||||
|
("header", h),
|
||||||
|
("method", meth)
|
||||||
|
]
|
||||||
|
|
||||||
|
instance JSONValue HttpRequest where
|
||||||
|
toJSONValue x =
|
||||||
|
makeObj $ requestObj x
|
||||||
|
|
||||||
|
data WasmFile = WasmFile
|
||||||
|
{
|
||||||
|
filePath :: String
|
||||||
|
, fileName :: Maybe String
|
||||||
|
, fileHash :: Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
instance JSONValue WasmFile where
|
||||||
|
toJSONValue x =
|
||||||
|
let path = makeString $ filePath x in
|
||||||
|
let name = stringOrNull $ fileName x in
|
||||||
|
let hash = stringOrNull $ fileHash x in
|
||||||
|
makeObj $ filterNulls [
|
||||||
|
("path", path),
|
||||||
|
("name", name),
|
||||||
|
("hash", hash)
|
||||||
|
]
|
||||||
|
|
||||||
|
data WasmCode = WasmCode
|
||||||
|
{
|
||||||
|
codeBytes :: B.ByteString
|
||||||
|
, codeName :: Maybe String
|
||||||
|
, codeHash :: Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
instance JSONValue WasmCode where
|
||||||
|
toJSONValue x =
|
||||||
|
let bytes = makeString $ BS.unpack $ B64.encode $ codeBytes x in
|
||||||
|
let name = stringOrNull $ codeName x in
|
||||||
|
let hash = stringOrNull $ codeHash x in
|
||||||
|
makeObj $ filterNulls [
|
||||||
|
("data", bytes),
|
||||||
|
("name", name),
|
||||||
|
("hash", hash)
|
||||||
|
]
|
||||||
|
|
||||||
|
data WasmURL = WasmURL
|
||||||
|
{
|
||||||
|
req :: HttpRequest
|
||||||
|
, urlName :: Maybe String
|
||||||
|
, urlHash :: Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
instance JSONValue WasmURL where
|
||||||
|
toJSONValue x =
|
||||||
|
let request = requestObj $ req x in
|
||||||
|
let name = stringOrNull $ urlName x in
|
||||||
|
let hash = stringOrNull $ urlHash x in
|
||||||
|
makeObj $ filterNulls $ ("name", name) : ("hash", hash) : request
|
||||||
|
|
||||||
|
data Wasm = File WasmFile | Code WasmCode | URL WasmURL
|
||||||
|
|
||||||
|
instance JSONValue Wasm where
|
||||||
|
toJSONValue x =
|
||||||
|
case x of
|
||||||
|
File f -> toJSONValue f
|
||||||
|
Code d -> toJSONValue d
|
||||||
|
URL u -> toJSONValue u
|
||||||
|
|
||||||
|
wasmFile :: String -> Wasm
|
||||||
|
wasmFile path =
|
||||||
|
File WasmFile { filePath = path, fileName = Nothing, fileHash = Nothing}
|
||||||
|
|
||||||
|
wasmURL :: String -> String -> Wasm
|
||||||
|
wasmURL method url =
|
||||||
|
let r = HttpRequest { url = url, header = [], method = Just method } in
|
||||||
|
URL WasmURL { req = r, urlName = Nothing, urlHash = Nothing }
|
||||||
|
|
||||||
|
wasmCode :: B.ByteString -> Wasm
|
||||||
|
wasmCode code =
|
||||||
|
Code WasmCode { codeBytes = code, codeName = Nothing, codeHash = Nothing }
|
||||||
|
|
||||||
|
withName :: Wasm -> String -> Wasm
|
||||||
|
withName (Code code) name = Code code { codeName = Just name }
|
||||||
|
withName (URL url) name = URL url { urlName = Just name }
|
||||||
|
withName (File f) name = File f { fileName = Just name }
|
||||||
|
|
||||||
|
|
||||||
|
withHash :: Wasm -> String -> Wasm
|
||||||
|
withHash (Code code) hash = Code code { codeHash = Just hash }
|
||||||
|
withHash (URL url) hash = URL url { urlHash = Just hash }
|
||||||
|
withHash (File f) hash = File f { fileHash = Just hash }
|
||||||
|
|
||||||
|
data Manifest = Manifest
|
||||||
|
{
|
||||||
|
wasm :: [Wasm]
|
||||||
|
, memory :: Maybe Memory
|
||||||
|
, config :: [(String, String)]
|
||||||
|
, allowed_hosts :: [String]
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest :: [Wasm] -> Manifest
|
||||||
|
manifest wasm =
|
||||||
|
Manifest {
|
||||||
|
wasm = wasm,
|
||||||
|
memory = Nothing,
|
||||||
|
config = [],
|
||||||
|
allowed_hosts = []
|
||||||
|
}
|
||||||
|
|
||||||
|
withConfig :: Manifest -> [(String, String)] -> Manifest
|
||||||
|
withConfig m config =
|
||||||
|
m { config = config }
|
||||||
|
|
||||||
|
|
||||||
|
withHosts :: Manifest -> [String] -> Manifest
|
||||||
|
withHosts m hosts =
|
||||||
|
m { allowed_hosts = hosts }
|
||||||
|
|
||||||
|
instance JSONValue Manifest where
|
||||||
|
toJSONValue x =
|
||||||
|
let w = makeArray toJSONValue $ wasm x in
|
||||||
|
let mem = valueOrNull toJSONValue $ memory x in
|
||||||
|
let c = mapObj makeString $ config x in
|
||||||
|
let hosts = makeArray makeString $ allowed_hosts x in
|
||||||
|
makeObj $ filterNulls [
|
||||||
|
("wasm", w),
|
||||||
|
("memory", mem),
|
||||||
|
("config", c),
|
||||||
|
("allowed_hosts", hosts)
|
||||||
|
]
|
||||||
|
|
||||||
|
toString :: Manifest -> String
|
||||||
|
toString manifest =
|
||||||
|
encode (toJSONValue manifest)
|
||||||
67
haskell/stack.yaml
Normal file
67
haskell/stack.yaml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# This file was automatically generated by 'stack init'
|
||||||
|
#
|
||||||
|
# Some commonly used options have been documented as comments in this file.
|
||||||
|
# For advanced use and comprehensive documentation of the format, please see:
|
||||||
|
# https://docs.haskellstack.org/en/stable/yaml_configuration/
|
||||||
|
|
||||||
|
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
|
||||||
|
# A snapshot resolver dictates the compiler version and the set of packages
|
||||||
|
# to be used for project dependencies. For example:
|
||||||
|
#
|
||||||
|
# resolver: lts-3.5
|
||||||
|
# resolver: nightly-2015-09-21
|
||||||
|
# resolver: ghc-7.10.2
|
||||||
|
#
|
||||||
|
# The location of a snapshot can be provided as a file or url. Stack assumes
|
||||||
|
# a snapshot provided as a file might change, whereas a url resource does not.
|
||||||
|
#
|
||||||
|
# resolver: ./custom-snapshot.yaml
|
||||||
|
# resolver: https://example.com/snapshots/2018-01-01.yaml
|
||||||
|
resolver:
|
||||||
|
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2022/8/30.yaml
|
||||||
|
|
||||||
|
# User packages to be built.
|
||||||
|
# Various formats can be used as shown in the example below.
|
||||||
|
#
|
||||||
|
# packages:
|
||||||
|
# - some-directory
|
||||||
|
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
|
||||||
|
# subdirs:
|
||||||
|
# - auto-update
|
||||||
|
# - wai
|
||||||
|
packages:
|
||||||
|
- .
|
||||||
|
# Dependency packages to be pulled from upstream that are not in the resolver.
|
||||||
|
# These entries can reference officially published versions as well as
|
||||||
|
# forks / in-progress versions pinned to a git hash. For example:
|
||||||
|
#
|
||||||
|
# extra-deps:
|
||||||
|
# - acme-missiles-0.3
|
||||||
|
# - git: https://github.com/commercialhaskell/stack.git
|
||||||
|
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
|
||||||
|
#
|
||||||
|
# extra-deps: []
|
||||||
|
|
||||||
|
# Override default flag values for local packages and extra-deps
|
||||||
|
# flags: {}
|
||||||
|
|
||||||
|
# Extra package databases containing global packages
|
||||||
|
# extra-package-dbs: []
|
||||||
|
|
||||||
|
# Control whether we use the GHC we find on the path
|
||||||
|
# system-ghc: true
|
||||||
|
#
|
||||||
|
# Require a specific version of stack, using version ranges
|
||||||
|
# require-stack-version: -any # Default
|
||||||
|
# require-stack-version: ">=2.7"
|
||||||
|
#
|
||||||
|
# Override the architecture used by stack, especially useful on Windows
|
||||||
|
# arch: i386
|
||||||
|
# arch: x86_64
|
||||||
|
#
|
||||||
|
# Extra directories used by stack for building
|
||||||
|
# extra-include-dirs: [/path/to/dir]
|
||||||
|
# extra-lib-dirs: [/path/to/dir]
|
||||||
|
#
|
||||||
|
# Allow a newer minor version of GHC than the snapshot specifies
|
||||||
|
# compiler-check: newer-minor
|
||||||
13
haskell/stack.yaml.lock
Normal file
13
haskell/stack.yaml.lock
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# This file was autogenerated by Stack.
|
||||||
|
# You should not edit this file by hand.
|
||||||
|
# For more information, please see the documentation at:
|
||||||
|
# https://docs.haskellstack.org/en/stable/lock_files
|
||||||
|
|
||||||
|
packages: []
|
||||||
|
snapshots:
|
||||||
|
- completed:
|
||||||
|
size: 632828
|
||||||
|
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2022/8/30.yaml
|
||||||
|
sha256: 5b02c2ce430ac62843fb884126765628da2ca2280bb9de0c6635c723e32a9f6b
|
||||||
|
original:
|
||||||
|
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2022/8/30.yaml
|
||||||
@@ -3,15 +3,18 @@ import Extism
|
|||||||
import Extism.Manifest
|
import Extism.Manifest
|
||||||
|
|
||||||
|
|
||||||
unwrap (Right x) = return x
|
unwrap' (Right x) = return x
|
||||||
unwrap (Left (ExtismError msg)) =
|
unwrap' (Left (ErrorMessage msg)) =
|
||||||
assertFailure msg
|
assertFailure msg
|
||||||
|
|
||||||
|
unwrap io = do
|
||||||
|
x <- io
|
||||||
|
unwrap' x
|
||||||
|
|
||||||
defaultManifest = manifest [wasmFile "test/code.wasm"]
|
defaultManifest = manifest [wasmFile "test/code.wasm"]
|
||||||
|
|
||||||
initPlugin :: Context -> IO Plugin
|
|
||||||
initPlugin context =
|
initPlugin context =
|
||||||
Extism.pluginFromManifest context defaultManifest False >>= unwrap
|
unwrap (Extism.pluginFromManifest context defaultManifest False)
|
||||||
|
|
||||||
pluginFunctionExists = do
|
pluginFunctionExists = do
|
||||||
withContext (\ctx -> do
|
withContext (\ctx -> do
|
||||||
@@ -22,7 +25,7 @@ pluginFunctionExists = do
|
|||||||
assertBool "function doesn't exist" (not exists'))
|
assertBool "function doesn't exist" (not exists'))
|
||||||
|
|
||||||
checkCallResult p = do
|
checkCallResult p = do
|
||||||
res <- call p "count_vowels" (toByteString "this is a test") >>= unwrap
|
res <- unwrap (call p "count_vowels" (toByteString "this is a test"))
|
||||||
assertEqual "count vowels output" "{\"count\": 4}" (fromByteString res)
|
assertEqual "count vowels output" "{\"count\": 4}" (fromByteString res)
|
||||||
|
|
||||||
pluginCall = do
|
pluginCall = do
|
||||||
@@ -42,7 +45,7 @@ pluginMultiple = do
|
|||||||
pluginUpdate = do
|
pluginUpdate = do
|
||||||
withContext (\ctx -> do
|
withContext (\ctx -> do
|
||||||
p <- initPlugin ctx
|
p <- initPlugin ctx
|
||||||
updateManifest p defaultManifest True >>= unwrap
|
unwrap (updateManifest p defaultManifest True)
|
||||||
checkCallResult p)
|
checkCallResult p)
|
||||||
|
|
||||||
pluginConfig = do
|
pluginConfig = do
|
||||||
@@ -52,7 +55,7 @@ pluginConfig = do
|
|||||||
assertBool "set config" b)
|
assertBool "set config" b)
|
||||||
|
|
||||||
testSetLogFile = do
|
testSetLogFile = do
|
||||||
b <- setLogFile "stderr" Extism.Error
|
b <- setLogFile "stderr" Error
|
||||||
assertBool "set log file" b
|
assertBool "set log file" b
|
||||||
|
|
||||||
t name f = TestLabel name (TestCase f)
|
t name f = TestLabel name (TestCase f)
|
||||||
|
|||||||
190
java/pom.xml
190
java/pom.xml
@@ -1,190 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.extism.sdk</groupId>
|
|
||||||
<artifactId>extism</artifactId>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
<version>0.1.0</version>
|
|
||||||
<name>extism</name>
|
|
||||||
<url>https://github.com/extism/extism</url>
|
|
||||||
<description>Java-SDK for Extism to use webassembly from Java</description>
|
|
||||||
|
|
||||||
<licenses>
|
|
||||||
<license>
|
|
||||||
<name>BSD 3-Clause</name>
|
|
||||||
<url>https://opensource.org/licenses/BSD-3-Clause</url>
|
|
||||||
</license>
|
|
||||||
</licenses>
|
|
||||||
|
|
||||||
<organization>
|
|
||||||
<name>Dylibso, Inc.</name>
|
|
||||||
<url>https://dylib.so</url>
|
|
||||||
</organization>
|
|
||||||
|
|
||||||
<developers>
|
|
||||||
<developer>
|
|
||||||
<name>The Extism Authors</name>
|
|
||||||
<email>oss@extism.org</email>
|
|
||||||
<roles>
|
|
||||||
<role>Maintainer</role>
|
|
||||||
</roles>
|
|
||||||
<organization>Dylibso, Inc.</organization>
|
|
||||||
<organizationUrl>https://dylib.so</organizationUrl>
|
|
||||||
</developer>
|
|
||||||
</developers>
|
|
||||||
|
|
||||||
<scm>
|
|
||||||
<connection>scm:git:git://github.com/extism/extism.git</connection>
|
|
||||||
<developerConnection>scm:git:ssh://git@github.com/extism/extism.git</developerConnection>
|
|
||||||
<url>https://github.com/extism/extism/java</url>
|
|
||||||
<tag>main</tag>
|
|
||||||
</scm>
|
|
||||||
|
|
||||||
<issueManagement>
|
|
||||||
<system>Github</system>
|
|
||||||
<url>https://github.com/extism/extism/issues</url>
|
|
||||||
</issueManagement>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<java.version>17</java.version>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
|
|
||||||
<!-- dependencies -->
|
|
||||||
<jna.version>5.12.1</jna.version>
|
|
||||||
<gson.version>2.10</gson.version>
|
|
||||||
|
|
||||||
<!-- testing -->
|
|
||||||
<junit-jupiter-engine.version>5.9.1</junit-jupiter-engine.version>
|
|
||||||
<assertj-core.version>3.23.1</assertj-core.version>
|
|
||||||
|
|
||||||
<!-- maven plugins -->
|
|
||||||
<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
|
|
||||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
|
||||||
|
|
||||||
<!-- jreleaser -->
|
|
||||||
<jreleaser.git.root.search>true</jreleaser.git.root.search>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>release</id>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>3.4.1</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>attach-javadoc</id>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
|
||||||
<version>3.2.1</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>attach-source</id>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.jreleaser</groupId>
|
|
||||||
<artifactId>jreleaser-maven-plugin</artifactId>
|
|
||||||
<version>1.3.1</version>
|
|
||||||
<configuration>
|
|
||||||
<jreleaser>
|
|
||||||
<release>
|
|
||||||
<github>
|
|
||||||
<skipRelease>true</skipRelease>
|
|
||||||
</github>
|
|
||||||
</release>
|
|
||||||
<signing>
|
|
||||||
<active>ALWAYS</active>
|
|
||||||
<armored>true</armored>
|
|
||||||
</signing>
|
|
||||||
<deploy>
|
|
||||||
<maven>
|
|
||||||
<nexus2>
|
|
||||||
<maven-central>
|
|
||||||
<active>ALWAYS</active>
|
|
||||||
<url>https://s01.oss.sonatype.org/service/local</url>
|
|
||||||
<!--
|
|
||||||
<closeRepository>false</closeRepository>
|
|
||||||
<releaseRepository>false</releaseRepository>
|
|
||||||
-->
|
|
||||||
<stagingRepositories>target/staging-deploy</stagingRepositories>
|
|
||||||
</maven-central>
|
|
||||||
</nexus2>
|
|
||||||
</maven>
|
|
||||||
</deploy>
|
|
||||||
</jreleaser>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<version>${maven-compiler-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<release>${java.version}</release>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<version>${maven-surefire-plugin.version}</version>
|
|
||||||
<configuration>
|
|
||||||
<systemPropertyVariables>
|
|
||||||
<jna.library.path>../target/release</jna.library.path>
|
|
||||||
</systemPropertyVariables>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.java.dev.jna</groupId>
|
|
||||||
<artifactId>jna</artifactId>
|
|
||||||
<version>${jna.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.code.gson</groupId>
|
|
||||||
<artifactId>gson</artifactId>
|
|
||||||
<version>${gson.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
|
||||||
<version>${junit-jupiter-engine.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.assertj</groupId>
|
|
||||||
<artifactId>assertj-core</artifactId>
|
|
||||||
<version>${assertj-core.version}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>uk.org.webcompere</groupId>
|
|
||||||
<artifactId>model-assert</artifactId>
|
|
||||||
<version>1.0.0</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
Extism Java-SDK
|
|
||||||
---
|
|
||||||
|
|
||||||
Java SDK for the [extism](https://extism.org/) WebAssembly Plugin-System.
|
|
||||||
|
|
||||||
# Build
|
|
||||||
|
|
||||||
To build the extism java-sdk run the following command:
|
|
||||||
|
|
||||||
```
|
|
||||||
mvn clean verify
|
|
||||||
```
|
|
||||||
|
|
||||||
# Usage
|
|
||||||
|
|
||||||
To use the extism java-sdk you need to add the `org.extism.sdk` dependency to your dependency management and ensure that
|
|
||||||
the native extism library is installed on your system. For installing the native library refer to the [extism documentation](https://extism.org/docs/install).
|
|
||||||
|
|
||||||
Instead of installing the native library on your system, you can also download the appropriate library for your platform
|
|
||||||
yourself.
|
|
||||||
To do that simply download the [extism release](https://github.com/extism/extism/releases) to a `folder` and run your java application with the system property `-Djna.library.path=/path/to/folder`.
|
|
||||||
|
|
||||||
## Maven
|
|
||||||
To use the extism java-sdk with maven you need to add the following dependency to your `pom.xml` file:
|
|
||||||
```xml
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.extism.sdk</groupId>
|
|
||||||
<artifactId>extism</artifactId>
|
|
||||||
<version>0.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Gradle
|
|
||||||
To use the extism java-sdk with maven you need to add the following dependency to your `build.gradle` file:
|
|
||||||
|
|
||||||
```
|
|
||||||
implementation 'org.extism.sdk:extism:0.1.0'
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package org.extism.sdk;
|
|
||||||
|
|
||||||
import com.sun.jna.Pointer;
|
|
||||||
import org.extism.sdk.manifest.Manifest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extism Context is used to store and manage plugins.
|
|
||||||
*/
|
|
||||||
public class Context implements AutoCloseable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds a pointer to the native ExtismContext struct.
|
|
||||||
*/
|
|
||||||
private final Pointer contextPointer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new context.
|
|
||||||
* <p>
|
|
||||||
* A Context is used to manage Plugins
|
|
||||||
* and make sure they are cleaned up when you are done with them.
|
|
||||||
*/
|
|
||||||
public Context() {
|
|
||||||
this.contextPointer = LibExtism.INSTANCE.extism_context_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new plugin managed by this context.
|
|
||||||
*
|
|
||||||
* @param manifest The manifest for the plugin
|
|
||||||
* @param withWASI Set to true to enable WASI
|
|
||||||
* @return the plugin instance
|
|
||||||
*/
|
|
||||||
public Plugin newPlugin(Manifest manifest, boolean withWASI) {
|
|
||||||
return new Plugin(this, manifest, withWASI);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees the context *and* frees all its Plugins. Use {@link #reset()}, if you just want to
|
|
||||||
* free the plugins but keep the context. You should ensure this is called when you are done
|
|
||||||
* with the context.
|
|
||||||
*/
|
|
||||||
public void free() {
|
|
||||||
LibExtism.INSTANCE.extism_context_free(this.contextPointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the context by freeing all its Plugins. Unlike {@link #free()}, it does not
|
|
||||||
* free the context itself.
|
|
||||||
*/
|
|
||||||
public void reset() {
|
|
||||||
LibExtism.INSTANCE.extism_context_reset(this.contextPointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the version string of the linked Extism Runtime.
|
|
||||||
*
|
|
||||||
* @return the version
|
|
||||||
*/
|
|
||||||
public String getVersion() {
|
|
||||||
return LibExtism.INSTANCE.extism_version();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the error associated with a context, if plugin is {@literal null} then the context error will be returned.
|
|
||||||
*
|
|
||||||
* @param plugin
|
|
||||||
* @return the error message
|
|
||||||
*/
|
|
||||||
protected String error(Plugin plugin) {
|
|
||||||
return LibExtism.INSTANCE.extism_error(this.contextPointer, plugin == null ? -1 : plugin.getIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the raw pointer to this context.
|
|
||||||
*
|
|
||||||
* @return the pointer
|
|
||||||
*/
|
|
||||||
public Pointer getPointer() {
|
|
||||||
return this.contextPointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls {@link #free()} if used in the context of a TWR block.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
this.free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package org.extism.sdk;
|
|
||||||
|
|
||||||
import org.extism.sdk.manifest.Manifest;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extism convenience functions.
|
|
||||||
*/
|
|
||||||
public class Extism {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure a log file with the given {@link Path} and configure the given {@link LogLevel}.
|
|
||||||
*
|
|
||||||
* @param path
|
|
||||||
* @param level
|
|
||||||
*
|
|
||||||
* @deprecated will be replaced with better logging API.
|
|
||||||
*/
|
|
||||||
@Deprecated(forRemoval = true)
|
|
||||||
public static void setLogFile(Path path, LogLevel level) {
|
|
||||||
|
|
||||||
Objects.requireNonNull(path, "path");
|
|
||||||
Objects.requireNonNull(level, "level");
|
|
||||||
|
|
||||||
var result = LibExtism.INSTANCE.extism_log_file(path.toString(), level.getLevel());
|
|
||||||
if (!result) {
|
|
||||||
var error = String.format("Could not set extism logger to %s with level %s", path, level);
|
|
||||||
throw new ExtismException(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invokes the named {@code function} from the {@link Manifest} with the given {@code input}.
|
|
||||||
*
|
|
||||||
* @param manifest the manifest containing the function
|
|
||||||
* @param function the name of the function to call
|
|
||||||
* @param input the input as string
|
|
||||||
* @return the output as string
|
|
||||||
* @throws ExtismException if the call fails
|
|
||||||
*/
|
|
||||||
public static String invokeFunction(Manifest manifest, String function, String input) throws ExtismException {
|
|
||||||
try (var ctx = new Context()) {
|
|
||||||
try (var plugin = ctx.newPlugin(manifest, false)) {
|
|
||||||
return plugin.call(function, input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error levels for the Extism logging facility.
|
|
||||||
*
|
|
||||||
* @see Extism#setLogFile(Path, LogLevel)
|
|
||||||
*/
|
|
||||||
public enum LogLevel {
|
|
||||||
|
|
||||||
INFO("info"), //
|
|
||||||
|
|
||||||
DEBUG("debug"), //
|
|
||||||
|
|
||||||
WARN("warn"), //
|
|
||||||
|
|
||||||
TRACE("trace");
|
|
||||||
|
|
||||||
private final String level;
|
|
||||||
|
|
||||||
LogLevel(String level) {
|
|
||||||
this.level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLevel() {
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package org.extism.sdk;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown when an exceptional condition has occurred.
|
|
||||||
*/
|
|
||||||
public class ExtismException extends RuntimeException {
|
|
||||||
|
|
||||||
public ExtismException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExtismException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExtismException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
package org.extism.sdk;
|
|
||||||
|
|
||||||
import com.sun.jna.Library;
|
|
||||||
import com.sun.jna.Native;
|
|
||||||
import com.sun.jna.Pointer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper around the Extism library.
|
|
||||||
*/
|
|
||||||
public interface LibExtism extends Library {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the extism library instance.
|
|
||||||
* Resolves the extism library based on the resolution algorithm defined in {@link com.sun.jna.NativeLibrary}.
|
|
||||||
*/
|
|
||||||
LibExtism INSTANCE = Native.load("extism", LibExtism.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new context
|
|
||||||
*/
|
|
||||||
Pointer extism_context_new();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free a context
|
|
||||||
*/
|
|
||||||
void extism_context_free(Pointer contextPointer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all plugins from the registry.
|
|
||||||
*
|
|
||||||
* @param contextPointer
|
|
||||||
*/
|
|
||||||
void extism_context_reset(Pointer contextPointer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the logger to the given path with the given level of verbosity
|
|
||||||
*
|
|
||||||
* @param path The file path of the logger
|
|
||||||
* @param logLevel The level of the logger
|
|
||||||
* @return true if successful
|
|
||||||
*/
|
|
||||||
boolean extism_log_file(String path, String logLevel);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the error associated with a @{@link Context} or @{@link Plugin}, if {@code pluginId} is {@literal -1} then the context error will be returned
|
|
||||||
*
|
|
||||||
* @param contextPointer
|
|
||||||
* @param pluginId
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
String extism_error(Pointer contextPointer, int pluginId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new plugin.
|
|
||||||
*
|
|
||||||
* @param contextPointer pointer to the {@link Context}.
|
|
||||||
* @param wasm is a WASM module (wat or wasm) or a JSON encoded manifest
|
|
||||||
* @param wasmSize the length of the `wasm` parameter
|
|
||||||
* @param withWASI enables/disables WASI
|
|
||||||
* @return id of the plugin or {@literal -1} in case of error
|
|
||||||
*/
|
|
||||||
int extism_plugin_new(long contextPointer, byte[] wasm, long wasmSize, boolean withWASI);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Extism version string
|
|
||||||
*/
|
|
||||||
String extism_version();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new plugin.
|
|
||||||
*
|
|
||||||
* @param contextPointer pointer to the {@link Context}.
|
|
||||||
* @param wasm is a WASM module (wat or wasm) or a JSON encoded manifest
|
|
||||||
* @param length the length of the `wasm` parameter
|
|
||||||
* @param withWASI enables/disables WASI
|
|
||||||
* @return id of the plugin or {@literal -1} in case of error
|
|
||||||
* @see #extism_plugin_new(long, byte[], long, boolean)
|
|
||||||
*/
|
|
||||||
int extism_plugin_new(Pointer contextPointer, byte[] wasm, int length, boolean withWASI);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls a function from the @{@link Plugin} at the given {@code pluginIndex}.
|
|
||||||
*
|
|
||||||
* @param contextPointer
|
|
||||||
* @param pluginIndex
|
|
||||||
* @param function_name is the function to call
|
|
||||||
* @param data is the data input data
|
|
||||||
* @param dataLength is the data input data length
|
|
||||||
* @return the result code of the plugin call. {@literal -1} in case of error, {@literal 0} otherwise.
|
|
||||||
*/
|
|
||||||
int extism_plugin_call(Pointer contextPointer, int pluginIndex, String function_name, byte[] data, int dataLength);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the length of a plugin's output data.
|
|
||||||
*
|
|
||||||
* @param contextPointer
|
|
||||||
* @param pluginIndex
|
|
||||||
* @return the length of the output data in bytes.
|
|
||||||
*/
|
|
||||||
int extism_plugin_output_length(Pointer contextPointer, int pluginIndex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the plugin's output data.
|
|
||||||
*
|
|
||||||
* @param contextPointer
|
|
||||||
* @param pluginIndex
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Pointer extism_plugin_output_data(Pointer contextPointer, int pluginIndex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a plugin, keeping the existing ID.
|
|
||||||
* Similar to {@link #extism_plugin_new(long, byte[], long, boolean)} but takes an {@code pluginIndex} argument to specify which plugin to update.
|
|
||||||
* Note: Memory for this plugin will be reset upon update.
|
|
||||||
*
|
|
||||||
* @param contextPointer
|
|
||||||
* @param pluginIndex
|
|
||||||
* @param wasm
|
|
||||||
* @param length
|
|
||||||
* @param withWASI
|
|
||||||
* @return {@literal true} if update was successful
|
|
||||||
*/
|
|
||||||
boolean extism_plugin_update(Pointer contextPointer, int pluginIndex, byte[] wasm, int length, boolean withWASI);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a plugin from the registry and free associated memory.
|
|
||||||
*
|
|
||||||
* @param contextPointer
|
|
||||||
* @param pluginIndex
|
|
||||||
*/
|
|
||||||
void extism_plugin_free(Pointer contextPointer, int pluginIndex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update plugin config values, this will merge with the existing values.
|
|
||||||
*
|
|
||||||
* @param contextPointer
|
|
||||||
* @param pluginIndex
|
|
||||||
* @param json
|
|
||||||
* @param jsonLength
|
|
||||||
* @return {@literal true} if update was successful
|
|
||||||
*/
|
|
||||||
boolean extism_plugin_config(Pointer contextPointer, int pluginIndex, byte[] json, int jsonLength);
|
|
||||||
}
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
package org.extism.sdk;
|
|
||||||
|
|
||||||
import com.sun.jna.Pointer;
|
|
||||||
import org.extism.sdk.manifest.Manifest;
|
|
||||||
import org.extism.sdk.support.JsonSerde;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a Extism plugin.
|
|
||||||
*/
|
|
||||||
public class Plugin implements AutoCloseable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the Extism {@link Context} that the plugin belongs to.
|
|
||||||
*/
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the index of the plugin
|
|
||||||
*/
|
|
||||||
private final int index;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for a Plugin. Only expose internally. Plugins should be created and
|
|
||||||
* managed from {@link org.extism.sdk.Context}.
|
|
||||||
*
|
|
||||||
* @param context The context to manage the plugin
|
|
||||||
* @param manifestBytes The manifest for the plugin
|
|
||||||
* @param withWASI Set to true to enable WASI
|
|
||||||
*/
|
|
||||||
public Plugin(Context context, byte[] manifestBytes, boolean withWASI) {
|
|
||||||
|
|
||||||
Objects.requireNonNull(context, "context");
|
|
||||||
Objects.requireNonNull(manifestBytes, "manifestBytes");
|
|
||||||
|
|
||||||
Pointer contextPointer = context.getPointer();
|
|
||||||
int index = LibExtism.INSTANCE.extism_plugin_new(contextPointer, manifestBytes, manifestBytes.length, withWASI);
|
|
||||||
if (index == -1) {
|
|
||||||
String error = context.error(this);
|
|
||||||
throw new ExtismException(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.index= index;
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Plugin(Context context, Manifest manifest, boolean withWASI) {
|
|
||||||
this(context, serialize(manifest), withWASI);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] serialize(Manifest manifest) {
|
|
||||||
Objects.requireNonNull(manifest, "manifest");
|
|
||||||
return JsonSerde.toJson(manifest).getBytes(StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for the internal index pointer to this plugin.
|
|
||||||
*
|
|
||||||
* @return the plugin index
|
|
||||||
*/
|
|
||||||
public int getIndex() {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke a function with the given name and input.
|
|
||||||
*
|
|
||||||
* @param functionName The name of the exported function to invoke
|
|
||||||
* @param inputData The raw bytes representing any input data
|
|
||||||
* @return A byte array representing the raw output data
|
|
||||||
* @throws ExtismException if the call fails
|
|
||||||
*/
|
|
||||||
public byte[] call(String functionName, byte[] inputData) {
|
|
||||||
|
|
||||||
Objects.requireNonNull(functionName, "functionName");
|
|
||||||
|
|
||||||
Pointer contextPointer = context.getPointer();
|
|
||||||
int inputDataLength = inputData == null ? 0 : inputData.length;
|
|
||||||
int exitCode = LibExtism.INSTANCE.extism_plugin_call(contextPointer, index, functionName, inputData, inputDataLength);
|
|
||||||
if (exitCode == -1) {
|
|
||||||
String error = context.error(this);
|
|
||||||
throw new ExtismException(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
int length = LibExtism.INSTANCE.extism_plugin_output_length(contextPointer, index);
|
|
||||||
Pointer output = LibExtism.INSTANCE.extism_plugin_output_data(contextPointer, index);
|
|
||||||
return output.getByteArray(0, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke a function with the given name and input.
|
|
||||||
*
|
|
||||||
* @param functionName The name of the exported function to invoke
|
|
||||||
* @param input The string representing the input data
|
|
||||||
* @return A string representing the output data
|
|
||||||
*/
|
|
||||||
public String call(String functionName, String input) {
|
|
||||||
|
|
||||||
Objects.requireNonNull(functionName, "functionName");
|
|
||||||
|
|
||||||
var inputBytes = input == null ? null : input.getBytes(StandardCharsets.UTF_8);
|
|
||||||
var outputBytes = call(functionName, inputBytes);
|
|
||||||
return new String(outputBytes, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the plugin code given manifest changes
|
|
||||||
*
|
|
||||||
* @param manifest The manifest for the plugin
|
|
||||||
* @param withWASI Set to true to enable WASI
|
|
||||||
* @return {@literal true} if update was successful
|
|
||||||
*/
|
|
||||||
public boolean update(Manifest manifest, boolean withWASI) {
|
|
||||||
return update(serialize(manifest), withWASI);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the plugin code given manifest changes
|
|
||||||
*
|
|
||||||
* @param manifestBytes The manifest for the plugin
|
|
||||||
* @param withWASI Set to true to enable WASI
|
|
||||||
* @return {@literal true} if update was successful
|
|
||||||
*/
|
|
||||||
public boolean update(byte[] manifestBytes, boolean withWASI) {
|
|
||||||
Objects.requireNonNull(manifestBytes, "manifestBytes");
|
|
||||||
return LibExtism.INSTANCE.extism_plugin_update(context.getPointer(), index, manifestBytes, manifestBytes.length, withWASI);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees a plugin from memory. Plugins will be automatically cleaned up
|
|
||||||
* if you free their parent Context using {@link org.extism.sdk.Context#free() free()} or {@link org.extism.sdk.Context#reset() reset()}
|
|
||||||
*/
|
|
||||||
public void free() {
|
|
||||||
LibExtism.INSTANCE.extism_plugin_free(context.getPointer(), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update plugin config values, this will merge with the existing values.
|
|
||||||
*
|
|
||||||
* @param json
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean updateConfig(String json) {
|
|
||||||
Objects.requireNonNull(json, "json");
|
|
||||||
return updateConfig(json.getBytes(StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update plugin config values, this will merge with the existing values.
|
|
||||||
*
|
|
||||||
* @param jsonBytes
|
|
||||||
* @return {@literal true} if update was successful
|
|
||||||
*/
|
|
||||||
public boolean updateConfig(byte[] jsonBytes) {
|
|
||||||
Objects.requireNonNull(jsonBytes, "jsonBytes");
|
|
||||||
return LibExtism.INSTANCE.extism_plugin_config(context.getPointer(), index, jsonBytes, jsonBytes.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls {@link #free()} if used in the context of a TWR block.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package org.extism.sdk.manifest;
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
import org.extism.sdk.wasm.WasmSource;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class Manifest {
|
|
||||||
|
|
||||||
@SerializedName("wasm")
|
|
||||||
private final List<WasmSource> sources;
|
|
||||||
|
|
||||||
@SerializedName("memory")
|
|
||||||
private final MemoryOptions memoryOptions;
|
|
||||||
|
|
||||||
// FIXME remove this and related stuff if not supported in java-sdk
|
|
||||||
@SerializedName("allowed_hosts")
|
|
||||||
private final List<String> allowedHosts;
|
|
||||||
|
|
||||||
@SerializedName("config")
|
|
||||||
private final Map<String, String> config;
|
|
||||||
|
|
||||||
public Manifest() {
|
|
||||||
this(new ArrayList<>(), null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Manifest(WasmSource source) {
|
|
||||||
this(List.of(source));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Manifest(List<WasmSource> sources) {
|
|
||||||
this(sources, null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Manifest(List<WasmSource> sources, MemoryOptions memoryOptions) {
|
|
||||||
this(sources, memoryOptions, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Manifest(List<WasmSource> sources, MemoryOptions memoryOptions, Map<String, String> config) {
|
|
||||||
this(sources, memoryOptions, config, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Manifest(List<WasmSource> sources, MemoryOptions memoryOptions, Map<String, String> config, List<String> allowedHosts) {
|
|
||||||
this.sources = sources;
|
|
||||||
this.memoryOptions = memoryOptions;
|
|
||||||
this.config = config;
|
|
||||||
this.allowedHosts = allowedHosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSource(WasmSource source) {
|
|
||||||
this.sources.add(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<WasmSource> getSources() {
|
|
||||||
return Collections.unmodifiableList(sources);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MemoryOptions getMemoryOptions() {
|
|
||||||
return memoryOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getConfig() {
|
|
||||||
if (config == null || config.isEmpty()) {
|
|
||||||
return Collections.emptyMap();
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableMap(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getAllowedHosts() {
|
|
||||||
if (allowedHosts == null || allowedHosts.isEmpty()) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return Collections.unmodifiableList(allowedHosts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package org.extism.sdk.manifest;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
// FIXME remove this and related stuff if not supported in java-sdk
|
|
||||||
public record ManifestHttpRequest(String url, Map<String, String> header, String method) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package org.extism.sdk.manifest;
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures memory for the Wasm runtime.
|
|
||||||
* Memory is described in units of pages (64KB) and represent contiguous chunks of addressable memory.
|
|
||||||
*
|
|
||||||
* @param max Max number of pages.
|
|
||||||
*/
|
|
||||||
public record MemoryOptions(@SerializedName("max") Integer max) {
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package org.extism.sdk.support;
|
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
|
|
||||||
public class Hashing {
|
|
||||||
|
|
||||||
public static String sha256HexDigest(byte[] input) {
|
|
||||||
try {
|
|
||||||
var messageDigest = MessageDigest.getInstance("SHA-256");
|
|
||||||
var messageDigestBytes = messageDigest.digest(input);
|
|
||||||
|
|
||||||
var hexString = new StringBuilder();
|
|
||||||
for (var b : messageDigestBytes) {
|
|
||||||
hexString.append(String.format("%02x", b));
|
|
||||||
}
|
|
||||||
return hexString.toString();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package org.extism.sdk.support;
|
|
||||||
|
|
||||||
import com.google.gson.FieldNamingPolicy;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.google.gson.JsonDeserializationContext;
|
|
||||||
import com.google.gson.JsonDeserializer;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
import com.google.gson.JsonSerializationContext;
|
|
||||||
import com.google.gson.JsonSerializer;
|
|
||||||
import org.extism.sdk.manifest.Manifest;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
public class JsonSerde {
|
|
||||||
|
|
||||||
private static final Gson GSON;
|
|
||||||
|
|
||||||
static {
|
|
||||||
GSON = new GsonBuilder() //
|
|
||||||
.disableHtmlEscaping() //
|
|
||||||
// needed to convert the byte[] to a base64 encoded String
|
|
||||||
.registerTypeHierarchyAdapter(byte[].class, new ByteArrayToBase64TypeAdapter()) //
|
|
||||||
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) //
|
|
||||||
.setPrettyPrinting() //
|
|
||||||
.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String toJson(Manifest manifest) {
|
|
||||||
return GSON.toJson(manifest);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ByteArrayToBase64TypeAdapter implements JsonSerializer<byte[]>, JsonDeserializer<byte[]> {
|
|
||||||
|
|
||||||
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
|
||||||
return Base64.getDecoder().decode(json.getAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
|
|
||||||
return new JsonPrimitive(Base64.getEncoder().withoutPadding().encodeToString(src));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package org.extism.sdk.wasm;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WASM Source represented by raw bytes.
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @param data the byte array representing the WASM code
|
|
||||||
* @param hash
|
|
||||||
*/
|
|
||||||
public record ByteArrayWasmSource(String name, byte[] data, String hash) implements WasmSource {
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package org.extism.sdk.wasm;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WASM Source represented by a file referenced by a path.
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @param path
|
|
||||||
* @param hash
|
|
||||||
*/
|
|
||||||
public record PathWasmSource(String name, String path, String hash) implements WasmSource {
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package org.extism.sdk.wasm;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A named WASM source.
|
|
||||||
*/
|
|
||||||
public interface WasmSource {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logical name of the WASM source
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
String name();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash of the WASM source
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
String hash();
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package org.extism.sdk.wasm;
|
|
||||||
|
|
||||||
import org.extism.sdk.ExtismException;
|
|
||||||
import org.extism.sdk.support.Hashing;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves {@link WasmSource} from {@link Path Path's} or raw bytes.
|
|
||||||
*/
|
|
||||||
public class WasmSourceResolver {
|
|
||||||
|
|
||||||
public PathWasmSource resolve(Path path) {
|
|
||||||
return resolve(null, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PathWasmSource resolve(String name, Path path) {
|
|
||||||
|
|
||||||
Objects.requireNonNull(path, "path");
|
|
||||||
|
|
||||||
var wasmFile = path.toFile();
|
|
||||||
var hash = hash(path);
|
|
||||||
var wasmName = name == null ? wasmFile.getName() : name;
|
|
||||||
|
|
||||||
return new PathWasmSource(wasmName, wasmFile.getAbsolutePath(), hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteArrayWasmSource resolve(String name, byte[] bytes) {
|
|
||||||
return new ByteArrayWasmSource(name, bytes, hash(bytes));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String hash(Path wasmFile) {
|
|
||||||
try {
|
|
||||||
return hash(Files.readAllBytes(wasmFile));
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new ExtismException("Could not compute hash from path: " + wasmFile, ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String hash(byte[] bytes) {
|
|
||||||
return Hashing.sha256HexDigest(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package org.extism.sdk;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
public class ContextTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldReturnVersionString() {
|
|
||||||
try (var ctx = new Context()) {
|
|
||||||
var version = ctx.getVersion();
|
|
||||||
assertThat(version).isNotNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldAllowResetOnEmptyContext() {
|
|
||||||
try (var ctx = new Context()) {
|
|
||||||
ctx.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package org.extism.sdk;
|
|
||||||
|
|
||||||
import org.extism.sdk.manifest.Manifest;
|
|
||||||
import org.extism.sdk.manifest.MemoryOptions;
|
|
||||||
import org.extism.sdk.support.JsonSerde;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.extism.sdk.TestWasmSources.CODE;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static uk.org.webcompere.modelassert.json.JsonAssertions.assertJson;
|
|
||||||
|
|
||||||
public class ManifestTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldSerializeManifestWithWasmSourceToJson() {
|
|
||||||
|
|
||||||
var manifest = new Manifest(CODE.pathWasmSource());
|
|
||||||
var json = JsonSerde.toJson(manifest);
|
|
||||||
assertNotNull(json);
|
|
||||||
|
|
||||||
assertJson(json).at("/wasm").isArray();
|
|
||||||
assertJson(json).at("/wasm").hasSize(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldSerializeManifestWithWasmSourceAndMemoryOptionsToJson() {
|
|
||||||
|
|
||||||
var manifest = new Manifest(List.of(CODE.pathWasmSource()), new MemoryOptions(4));
|
|
||||||
var json = JsonSerde.toJson(manifest);
|
|
||||||
assertNotNull(json);
|
|
||||||
|
|
||||||
assertJson(json).at("/wasm").isArray();
|
|
||||||
assertJson(json).at("/wasm").hasSize(1);
|
|
||||||
assertJson(json).at("/memory/max").isEqualTo(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void codeWasmFromFileAndBytesShouldProduceTheSameHash() {
|
|
||||||
|
|
||||||
var byteHash = CODE.byteArrayWasmSource().hash();
|
|
||||||
var fileHash = CODE.pathWasmSource().hash();
|
|
||||||
|
|
||||||
assertThat(byteHash).isEqualTo(fileHash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
package org.extism.sdk;
|
|
||||||
|
|
||||||
import org.extism.sdk.manifest.Manifest;
|
|
||||||
import org.extism.sdk.manifest.MemoryOptions;
|
|
||||||
import org.extism.sdk.wasm.WasmSourceResolver;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.extism.sdk.TestWasmSources.CODE;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
|
|
||||||
public class PluginTests {
|
|
||||||
|
|
||||||
// static {
|
|
||||||
// Extism.setLogFile(Paths.get("/tmp/extism.log"), Extism.LogLevel.TRACE);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldInvokeFunctionWithMemoryOptions() {
|
|
||||||
//FIXME check whether memory options are effective
|
|
||||||
var manifest = new Manifest(List.of(CODE.pathWasmSource()), new MemoryOptions(0));
|
|
||||||
var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
|
|
||||||
assertThat(output).isEqualTo("{\"count\": 3}");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldInvokeFunctionWithConfig() {
|
|
||||||
//FIXME check if config options are available in wasm call
|
|
||||||
var config = Map.of("key1", "value1");
|
|
||||||
var manifest = new Manifest(List.of(CODE.pathWasmSource()), null, config);
|
|
||||||
var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
|
|
||||||
assertThat(output).isEqualTo("{\"count\": 3}");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldInvokeFunctionFromFileWasmSource() {
|
|
||||||
var manifest = new Manifest(CODE.pathWasmSource());
|
|
||||||
var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
|
|
||||||
assertThat(output).isEqualTo("{\"count\": 3}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO This test breaks on CI with error:
|
|
||||||
// data did not match any variant of untagged enum Wasm at line 8 column 3
|
|
||||||
// @Test
|
|
||||||
// public void shouldInvokeFunctionFromByteArrayWasmSource() {
|
|
||||||
// var manifest = new Manifest(CODE.byteArrayWasmSource());
|
|
||||||
// var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
|
|
||||||
// assertThat(output).isEqualTo("{\"count\": 3}");
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldFailToInvokeUnknownFunction() {
|
|
||||||
assertThrows(ExtismException.class, () -> {
|
|
||||||
var manifest = new Manifest(CODE.pathWasmSource());
|
|
||||||
Extism.invokeFunction(manifest, "unknown", "dummy");
|
|
||||||
}, "Function not found: unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldAllowInvokeFunctionFromFileWasmSourceMultipleTimes() {
|
|
||||||
var wasmSource = CODE.pathWasmSource();
|
|
||||||
var manifest = new Manifest(wasmSource);
|
|
||||||
var output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
|
|
||||||
assertThat(output).isEqualTo("{\"count\": 3}");
|
|
||||||
|
|
||||||
output = Extism.invokeFunction(manifest, "count_vowels", "Hello World");
|
|
||||||
assertThat(output).isEqualTo("{\"count\": 3}");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldAllowInvokeFunctionFromFileWasmSourceApiUsageExample() {
|
|
||||||
|
|
||||||
var wasmSourceResolver = new WasmSourceResolver();
|
|
||||||
var manifest = new Manifest(wasmSourceResolver.resolve(CODE.getWasmFilePath()));
|
|
||||||
|
|
||||||
var functionName = "count_vowels";
|
|
||||||
var input = "Hello World";
|
|
||||||
|
|
||||||
try (var ctx = new Context()) {
|
|
||||||
try (var plugin = ctx.newPlugin(manifest, false)) {
|
|
||||||
var output = plugin.call(functionName, input);
|
|
||||||
assertThat(output).isEqualTo("{\"count\": 3}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldAllowInvokeFunctionFromFileWasmSourceMultipleTimesByReusingContext() {
|
|
||||||
var manifest = new Manifest(CODE.pathWasmSource());
|
|
||||||
var functionName = "count_vowels";
|
|
||||||
var input = "Hello World";
|
|
||||||
|
|
||||||
try (var ctx = new Context()) {
|
|
||||||
try (var plugin = ctx.newPlugin(manifest, false)) {
|
|
||||||
var output = plugin.call(functionName, input);
|
|
||||||
assertThat(output).isEqualTo("{\"count\": 3}");
|
|
||||||
|
|
||||||
output = plugin.call(functionName, input);
|
|
||||||
assertThat(output).isEqualTo("{\"count\": 3}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package org.extism.sdk;
|
|
||||||
|
|
||||||
import org.extism.sdk.wasm.ByteArrayWasmSource;
|
|
||||||
import org.extism.sdk.wasm.PathWasmSource;
|
|
||||||
import org.extism.sdk.wasm.WasmSourceResolver;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public enum TestWasmSources {
|
|
||||||
|
|
||||||
CODE {
|
|
||||||
public Path getWasmFilePath() {
|
|
||||||
return Paths.get(WASM_LOCATION, "code.wasm");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final String WASM_LOCATION = "src/test/resources";
|
|
||||||
|
|
||||||
public abstract Path getWasmFilePath();
|
|
||||||
|
|
||||||
public PathWasmSource pathWasmSource() {
|
|
||||||
return resolvePathWasmSource(getWasmFilePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteArrayWasmSource byteArrayWasmSource() {
|
|
||||||
try {
|
|
||||||
var wasmBytes = Files.readAllBytes(getWasmFilePath());
|
|
||||||
return new WasmSourceResolver().resolve("wasm@" + Arrays.hashCode(wasmBytes), wasmBytes);
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new RuntimeException(ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PathWasmSource resolvePathWasmSource(Path path) {
|
|
||||||
return new WasmSourceResolver().resolve(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -5,6 +5,6 @@ libdir=${exec_prefix}/lib
|
|||||||
|
|
||||||
Name: extism
|
Name: extism
|
||||||
Description: The Extism universal plug-in system.
|
Description: The Extism universal plug-in system.
|
||||||
Version: 0.1.0
|
Version: 0.0.1
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
Libs: -L${libdir} -lextism
|
Libs: -L${libdir} -lextism
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "libextism"
|
name = "libextism"
|
||||||
version = "0.1.0"
|
version = "0.0.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["The Extism Authors", "oss@extism.org"]
|
authors = ["The Extism Authors", "oss@extism.org"]
|
||||||
license = "BSD-3-Clause"
|
license = "BSD-3-Clause"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user