mirror of
https://github.com/extism/extism.git
synced 2026-01-12 15:28:05 -05:00
Compare commits
14 Commits
fix-releas
...
v0.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37b8e5bd12 | ||
|
|
c6b8429c67 | ||
|
|
ad114f44d2 | ||
|
|
45180ad473 | ||
|
|
9546dac689 | ||
|
|
197e934258 | ||
|
|
339556597b | ||
|
|
64927d9bcd | ||
|
|
86f1117ad5 | ||
|
|
34be80a7ad | ||
|
|
3e6a0071e9 | ||
|
|
d17b693c4b | ||
|
|
18fceec8f8 | ||
|
|
f5cf4f184e |
8
.github/workflows/release-elixir.yaml
vendored
8
.github/workflows/release-elixir.yaml
vendored
@@ -10,7 +10,13 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install extism shared library
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p /home/runner/.local/bin/
|
||||
export PATH="/home/runner/.local/bin/:$PATH"
|
||||
curl https://raw.githubusercontent.com/extism/cli/main/install.sh | sh
|
||||
extism --sudo --prefix /usr/local install
|
||||
- name: Setup Elixir Host SDK
|
||||
uses: erlef/setup-beam@v1
|
||||
with:
|
||||
|
||||
1
.github/workflows/release-python.yaml
vendored
1
.github/workflows/release-python.yaml
vendored
@@ -23,7 +23,6 @@ jobs:
|
||||
run: |
|
||||
cd python
|
||||
cp ../LICENSE .
|
||||
cp ../README.md .
|
||||
make clean
|
||||
make prepare
|
||||
poetry build
|
||||
|
||||
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 }}
|
||||
run: |
|
||||
cd ruby
|
||||
make publish
|
||||
make publish RUBYGEMS_API_KEY=$RUBYGEMS_API_KEY
|
||||
|
||||
25
browser/Makefile
Normal file
25
browser/Makefile
Normal file
@@ -0,0 +1,25 @@
|
||||
.PHONY: test
|
||||
|
||||
prepare:
|
||||
npm install
|
||||
|
||||
test: prepare
|
||||
npm run test
|
||||
|
||||
clean:
|
||||
echo "No clean implemented"
|
||||
|
||||
publish: clean prepare
|
||||
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
|
||||
1019
browser/package-lock.json
generated
1019
browser/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@extism/runtime-browser",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.0",
|
||||
"description": "Extism runtime in the browser",
|
||||
"scripts": {
|
||||
"build": "node build.js && tsc --emitDeclarationOnly --outDir dist",
|
||||
|
||||
@@ -12,7 +12,7 @@ describe('', () => {
|
||||
const ctx = new ExtismContext();
|
||||
const plugin = await ctx.newPlugin({ wasm: [{ data: data }] });
|
||||
const functions = await plugin.getExports();
|
||||
expect(Object.keys(functions).filter(x => !x.startsWith("__") && x !== "memory")).toEqual(['count_vowels']);
|
||||
expect(Object.keys(functions).filter((x) => !x.startsWith('__') && x !== 'memory')).toEqual(['count_vowels']);
|
||||
let output = await plugin.call('count_vowels', 'this is a test');
|
||||
expect(parse(output)).toEqual({ count: 4 });
|
||||
output = await plugin.call('count_vowels', 'this is a test again');
|
||||
|
||||
@@ -4,8 +4,8 @@ defmodule Extism.MixProject do
|
||||
def project do
|
||||
[
|
||||
app: :extism,
|
||||
version: "0.0.1",
|
||||
elixir: "~> 1.14",
|
||||
version: "0.1.0",
|
||||
elixir: "~> 1.12",
|
||||
start_permanent: Mix.env() == :prod,
|
||||
deps: deps(),
|
||||
package: package(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "extism_nif"
|
||||
version = "0.0.1-rc.6"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Benjamin Eckel <bhelx@simst.im>"]
|
||||
|
||||
@@ -11,5 +11,5 @@ crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
rustler = "0.26.0"
|
||||
extism = { version = "0.0.1-rc.6" }
|
||||
extism = { version = "0.1.0" }
|
||||
log = "0.4"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use rustler::{Atom, Env, Term, ResourceArc};
|
||||
use extism::{Plugin, Context};
|
||||
use std::str;
|
||||
use extism::{Context, Plugin};
|
||||
use rustler::{Atom, Env, ResourceArc, Term};
|
||||
use std::mem;
|
||||
use std::path::Path;
|
||||
use std::str;
|
||||
use std::str::FromStr;
|
||||
use std::sync::RwLock;
|
||||
use std::mem;
|
||||
|
||||
mod atoms {
|
||||
rustler::atoms! {
|
||||
@@ -15,9 +15,12 @@ mod atoms {
|
||||
}
|
||||
|
||||
struct ExtismContext {
|
||||
ctx: RwLock<Context>
|
||||
ctx: RwLock<Context>,
|
||||
}
|
||||
|
||||
unsafe impl Sync for ExtismContext {}
|
||||
unsafe impl Send for ExtismContext {}
|
||||
|
||||
fn load(env: Env, _: Term) -> bool {
|
||||
rustler::resource!(ExtismContext, env);
|
||||
true
|
||||
@@ -27,15 +30,16 @@ fn to_rustler_error(extism_error: extism::Error) -> rustler::Error {
|
||||
match extism_error {
|
||||
extism::Error::UnableToLoadPlugin(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]
|
||||
fn context_new() -> ResourceArc<ExtismContext> {
|
||||
ResourceArc::new(
|
||||
ExtismContext { ctx: RwLock::new(Context::new()) }
|
||||
)
|
||||
ResourceArc::new(ExtismContext {
|
||||
ctx: RwLock::new(Context::new()),
|
||||
})
|
||||
}
|
||||
|
||||
#[rustler::nif]
|
||||
@@ -51,7 +55,11 @@ fn context_free(ctx: ResourceArc<ExtismContext>) {
|
||||
}
|
||||
|
||||
#[rustler::nif]
|
||||
fn plugin_new_with_manifest(ctx: ResourceArc<ExtismContext>, manifest_payload: String, wasi: bool) -> Result<i32, rustler::Error> {
|
||||
fn plugin_new_with_manifest(
|
||||
ctx: ResourceArc<ExtismContext>,
|
||||
manifest_payload: String,
|
||||
wasi: bool,
|
||||
) -> Result<i32, rustler::Error> {
|
||||
let context = &ctx.ctx.write().unwrap();
|
||||
let result = match Plugin::new(context, manifest_payload, wasi) {
|
||||
Err(e) => Err(to_rustler_error(e)),
|
||||
@@ -67,17 +75,22 @@ fn plugin_new_with_manifest(ctx: ResourceArc<ExtismContext>, manifest_payload: S
|
||||
}
|
||||
|
||||
#[rustler::nif]
|
||||
fn plugin_call(ctx: ResourceArc<ExtismContext>, plugin_id: i32, name: String, input: String) -> Result<String, rustler::Error> {
|
||||
fn plugin_call(
|
||||
ctx: ResourceArc<ExtismContext>,
|
||||
plugin_id: i32,
|
||||
name: String,
|
||||
input: String,
|
||||
) -> Result<String, rustler::Error> {
|
||||
let context = &ctx.ctx.read().unwrap();
|
||||
let plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
||||
let mut plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
||||
let result = match plugin.call(name, input) {
|
||||
Err(e) => Err(to_rustler_error(e)),
|
||||
Ok(result) => {
|
||||
match str::from_utf8(&result) {
|
||||
Ok(output) => Ok(output.to_string()),
|
||||
Err(_e) => Err(rustler::Error::Term(Box::new("Could not read output from plugin")))
|
||||
}
|
||||
}
|
||||
Ok(result) => match str::from_utf8(&result) {
|
||||
Ok(output) => Ok(output.to_string()),
|
||||
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
|
||||
// all it's plugins when it is dropped
|
||||
@@ -86,14 +99,17 @@ fn plugin_call(ctx: ResourceArc<ExtismContext>, plugin_id: i32, name: String, in
|
||||
}
|
||||
|
||||
#[rustler::nif]
|
||||
fn plugin_update_manifest(ctx: ResourceArc<ExtismContext>, plugin_id: i32, manifest_payload: String, wasi: bool) -> Result<(), rustler::Error> {
|
||||
fn plugin_update_manifest(
|
||||
ctx: ResourceArc<ExtismContext>,
|
||||
plugin_id: i32,
|
||||
manifest_payload: String,
|
||||
wasi: bool,
|
||||
) -> Result<(), rustler::Error> {
|
||||
let context = &ctx.ctx.read().unwrap();
|
||||
let mut plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
||||
let result = match plugin.update(manifest_payload, wasi) {
|
||||
Ok(()) => {
|
||||
Ok(())
|
||||
},
|
||||
Err(e) => Err(to_rustler_error(e))
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(to_rustler_error(e)),
|
||||
};
|
||||
// this forget should be safe because the context will clean up
|
||||
// all it's plugins when it is dropped
|
||||
@@ -113,19 +129,28 @@ fn plugin_free(ctx: ResourceArc<ExtismContext>, plugin_id: i32) -> Result<(), ru
|
||||
fn set_log_file(filename: String, log_level: String) -> Result<Atom, rustler::Error> {
|
||||
let path = Path::new(&filename);
|
||||
match log::Level::from_str(&log_level) {
|
||||
Err(_e) => Err(rustler::Error::Term(Box::new(format!("{} not a valid log level", log_level)))),
|
||||
Err(_e) => Err(rustler::Error::Term(Box::new(format!(
|
||||
"{} not a valid log level",
|
||||
log_level
|
||||
)))),
|
||||
Ok(level) => {
|
||||
if extism::set_log_file(path, Some(level)) {
|
||||
Ok(atoms::ok())
|
||||
} else {
|
||||
Err(rustler::Error::Term(Box::new("Did not set log file, received false from the API.")))
|
||||
Err(rustler::Error::Term(Box::new(
|
||||
"Did not set log file, received false from the API.",
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[rustler::nif]
|
||||
fn plugin_has_function(ctx: ResourceArc<ExtismContext>, plugin_id: i32, function_name: String) -> Result<bool, rustler::Error> {
|
||||
fn plugin_has_function(
|
||||
ctx: ResourceArc<ExtismContext>,
|
||||
plugin_id: i32,
|
||||
function_name: String,
|
||||
) -> Result<bool, rustler::Error> {
|
||||
let context = &ctx.ctx.read().unwrap();
|
||||
let plugin = unsafe { Plugin::from_id(plugin_id, context) };
|
||||
let has_function = plugin.has_function(function_name);
|
||||
|
||||
@@ -18,6 +18,6 @@ handlePlugin plugin = do
|
||||
exitSuccess) res
|
||||
|
||||
main = do
|
||||
context <- Extism.newContext ()
|
||||
context <- Extism.newContext
|
||||
plugin <- Extism.pluginFromManifest context (manifest [wasmFile "../wasm/code.wasm"]) False
|
||||
try handlePlugin plugin
|
||||
@@ -1,4 +1,4 @@
|
||||
cabal-version: 2.4
|
||||
cabal-version: 3.0
|
||||
name: extism
|
||||
version: 0.0.1
|
||||
|
||||
@@ -23,22 +23,41 @@ category: Plugins, WebAssembly
|
||||
extra-source-files: CHANGELOG.md
|
||||
|
||||
library
|
||||
exposed-modules: Extism Extism.Manifest
|
||||
exposed-modules: Extism
|
||||
reexported-modules: Extism.Manifest
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
other-modules: Extism.Bindings
|
||||
|
||||
-- LANGUAGE extensions used by modules in this package.
|
||||
-- other-extensions:
|
||||
build-depends:
|
||||
base >= 1.6.0
|
||||
, bytestring
|
||||
, json
|
||||
, manifest
|
||||
hs-source-dirs: src
|
||||
default-language: Haskell2010
|
||||
extra-libraries: extism
|
||||
extra-lib-dirs: /usr/local/lib
|
||||
|
||||
library manifest
|
||||
exposed-modules: Extism.Manifest
|
||||
|
||||
visibility: public
|
||||
|
||||
-- Modules included in this library but not exported.
|
||||
other-modules:
|
||||
|
||||
-- LANGUAGE extensions used by modules in this package.
|
||||
-- other-extensions:
|
||||
build-depends:
|
||||
base ^>=4.16.1.0
|
||||
base
|
||||
, bytestring
|
||||
, base64-bytestring
|
||||
, json
|
||||
hs-source-dirs: src
|
||||
hs-source-dirs: manifest
|
||||
default-language: Haskell2010
|
||||
extra-libraries: extism
|
||||
extra-lib-dirs: /usr/local/lib
|
||||
|
||||
Test-Suite extism-example
|
||||
type: exitcode-stdio-1.0
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
|
||||
|
||||
module Extism.Manifest where
|
||||
|
||||
import Text.JSON
|
||||
(
|
||||
JSON,
|
||||
JSValue(JSNull, JSString, JSArray),
|
||||
toJSString, showJSON, makeObj, encode
|
||||
)
|
||||
@@ -9,16 +12,12 @@ 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])
|
||||
makeArray x = JSArray [toJSONValue a | a <- x]
|
||||
isNull JSNull = True
|
||||
isNull _ = False
|
||||
filterNulls obj = [(a, b) | (a, b) <- obj, not (isNull b)]
|
||||
object x = makeObj $ filterNulls x
|
||||
(.=) a b = (a, toJSONValue b)
|
||||
|
||||
newtype Memory = Memory
|
||||
{
|
||||
@@ -27,32 +26,37 @@ newtype Memory = Memory
|
||||
|
||||
class JSONValue a where
|
||||
toJSONValue :: a -> JSValue
|
||||
|
||||
instance {-# OVERLAPS #-} (JSON a) => (JSONValue a) where
|
||||
toJSONValue j = showJSON j
|
||||
|
||||
instance {-# OVERLAPS #-} (JSONValue a) => (JSONValue (Maybe a)) where
|
||||
toJSONValue Nothing = JSNull
|
||||
toJSONValue (Just x) = toJSONValue x
|
||||
|
||||
instance JSONValue Memory where
|
||||
toJSONValue x =
|
||||
case memoryMax x of
|
||||
Nothing -> makeObj []
|
||||
Just max -> makeObj [("max", showJSON max)]
|
||||
toJSONValue (Memory max) =
|
||||
object [
|
||||
"max" .= max
|
||||
]
|
||||
|
||||
data HttpRequest = HttpRequest
|
||||
data HTTPRequest = HTTPRequest
|
||||
{
|
||||
url :: String
|
||||
, header :: [(String, String)]
|
||||
, header :: Maybe [(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)
|
||||
requestObj (HTTPRequest url header method) =
|
||||
[
|
||||
"url" .= url ,
|
||||
"header" .= header,
|
||||
"method" .= method
|
||||
]
|
||||
|
||||
instance JSONValue HttpRequest where
|
||||
instance JSONValue HTTPRequest where
|
||||
toJSONValue x =
|
||||
makeObj $ requestObj x
|
||||
object $ requestObj x
|
||||
|
||||
data WasmFile = WasmFile
|
||||
{
|
||||
@@ -62,14 +66,11 @@ data WasmFile = WasmFile
|
||||
}
|
||||
|
||||
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)
|
||||
toJSONValue (WasmFile path name hash) =
|
||||
object [
|
||||
"path" .= path,
|
||||
"name" .= name,
|
||||
"hash" .= hash
|
||||
]
|
||||
|
||||
data WasmCode = WasmCode
|
||||
@@ -81,30 +82,26 @@ data WasmCode = WasmCode
|
||||
|
||||
|
||||
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)
|
||||
toJSONValue (WasmCode x name hash) =
|
||||
let bytes = BS.unpack $ B64.encode x in
|
||||
object [
|
||||
"data" .= bytes,
|
||||
"name" .= name,
|
||||
"hash" .= hash
|
||||
]
|
||||
|
||||
data WasmURL = WasmURL
|
||||
{
|
||||
req :: HttpRequest
|
||||
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
|
||||
toJSONValue (WasmURL req name hash) =
|
||||
let request = requestObj $ req in
|
||||
object $ "name" .= name : "hash" .= hash : request
|
||||
|
||||
data Wasm = File WasmFile | Code WasmCode | URL WasmURL
|
||||
|
||||
@@ -121,7 +118,7 @@ wasmFile path =
|
||||
|
||||
wasmURL :: String -> String -> Wasm
|
||||
wasmURL method url =
|
||||
let r = HttpRequest { url = url, header = [], method = Just method } in
|
||||
let r = HTTPRequest { url = url, header = Nothing, method = Just method } in
|
||||
URL WasmURL { req = r, urlName = Nothing, urlHash = Nothing }
|
||||
|
||||
wasmCode :: B.ByteString -> Wasm
|
||||
@@ -143,8 +140,8 @@ data Manifest = Manifest
|
||||
{
|
||||
wasm :: [Wasm]
|
||||
, memory :: Maybe Memory
|
||||
, config :: [(String, String)]
|
||||
, allowed_hosts :: [String]
|
||||
, config :: Maybe [(String, String)]
|
||||
, allowedHosts :: Maybe [String]
|
||||
}
|
||||
|
||||
manifest :: [Wasm] -> Manifest
|
||||
@@ -152,32 +149,29 @@ manifest wasm =
|
||||
Manifest {
|
||||
wasm = wasm,
|
||||
memory = Nothing,
|
||||
config = [],
|
||||
allowed_hosts = []
|
||||
config = Nothing,
|
||||
allowedHosts = Nothing
|
||||
}
|
||||
|
||||
withConfig :: Manifest -> [(String, String)] -> Manifest
|
||||
withConfig m config =
|
||||
m { config = config }
|
||||
m { config = Just config }
|
||||
|
||||
|
||||
withHosts :: Manifest -> [String] -> Manifest
|
||||
withHosts m hosts =
|
||||
m { allowed_hosts = hosts }
|
||||
m { allowedHosts = Just 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)
|
||||
toJSONValue (Manifest wasm memory config hosts) =
|
||||
let w = makeArray wasm in
|
||||
object [
|
||||
"wasm" .= w,
|
||||
"memory" .= memory,
|
||||
"config" .= config,
|
||||
"allowed_hosts" .= hosts
|
||||
]
|
||||
|
||||
toString :: Manifest -> String
|
||||
toString manifest =
|
||||
encode (toJSONValue manifest)
|
||||
toString :: (JSONValue a) => a -> String
|
||||
toString v =
|
||||
encode (toJSONValue v)
|
||||
@@ -1,36 +1,17 @@
|
||||
{-# LANGUAGE ForeignFunctionInterface #-}
|
||||
|
||||
module Extism (module Extism, module Extism.Manifest) where
|
||||
import GHC.Int
|
||||
import GHC.Word
|
||||
import Foreign.C.Types
|
||||
import Foreign.Ptr
|
||||
import Data.Int
|
||||
import Data.Word
|
||||
import Control.Monad (void)
|
||||
import Foreign.ForeignPtr
|
||||
import Foreign.C.String
|
||||
import Control.Monad (void)
|
||||
import Foreign.Ptr
|
||||
import Data.ByteString as B
|
||||
import Data.ByteString.Internal (c2w, w2c)
|
||||
import Data.ByteString.Unsafe (unsafeUseAsCString)
|
||||
import Data.Bifunctor (second)
|
||||
import Text.JSON (JSON, toJSObject, toJSString, encode, JSValue(JSNull, JSString))
|
||||
import Extism.Manifest (Manifest, toString)
|
||||
|
||||
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
|
||||
import Text.JSON (encode, toJSObject)
|
||||
import Extism.Manifest (Manifest, toString, toJSONValue)
|
||||
import Extism.Bindings
|
||||
|
||||
-- Context manages plugins
|
||||
newtype Context = Context (ForeignPtr ExtismContext)
|
||||
@@ -64,8 +45,8 @@ reset (Context ctx) =
|
||||
withForeignPtr ctx extism_context_reset
|
||||
|
||||
-- Create a new context
|
||||
newContext :: () -> IO Context
|
||||
newContext () = do
|
||||
newContext :: IO Context
|
||||
newContext = do
|
||||
ptr <- extism_context_new
|
||||
fptr <- newForeignPtr extism_context_free ptr
|
||||
return (Context fptr)
|
||||
@@ -73,7 +54,7 @@ newContext () = do
|
||||
-- Execute a function with a new context that is destroyed when it returns
|
||||
withContext :: (Context -> IO a) -> IO a
|
||||
withContext f = do
|
||||
ctx <- newContext ()
|
||||
ctx <- newContext
|
||||
f ctx
|
||||
|
||||
-- Create a plugin from a WASM module, `useWasi` determines if WASI should
|
||||
@@ -126,16 +107,13 @@ updateManifest plugin manifest useWasi =
|
||||
isValid :: Plugin -> Bool
|
||||
isValid (Plugin _ p) = p >= 0
|
||||
|
||||
convertMaybeString Nothing = JSNull
|
||||
convertMaybeString (Just s) = JSString (toJSString s)
|
||||
|
||||
-- Set configuration values for a plugin
|
||||
setConfig :: Plugin -> [(String, Maybe String)] -> IO Bool
|
||||
setConfig (Plugin (Context ctx) plugin) x =
|
||||
if plugin < 0
|
||||
then return False
|
||||
else
|
||||
let obj = toJSObject [(k, convertMaybeString v) | (k, v) <- x] in
|
||||
let obj = toJSObject [(k, toJSONValue v) | (k, v) <- x] in
|
||||
let bs = toByteString (encode obj) in
|
||||
let length = fromIntegral (B.length bs) in
|
||||
unsafeUseAsCString bs (\s -> do
|
||||
|
||||
26
haskell/src/Extism/Bindings.hs
Normal file
26
haskell/src/Extism/Bindings.hs
Normal file
@@ -0,0 +1,26 @@
|
||||
{-# 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
|
||||
@@ -5,6 +5,6 @@ libdir=${exec_prefix}/lib
|
||||
|
||||
Name: extism
|
||||
Description: The Extism universal plug-in system.
|
||||
Version: 0.0.1
|
||||
Version: 0.1.0
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lextism
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libextism"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["The Extism Authors", "oss@extism.org"]
|
||||
license = "BSD-3-Clause"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "extism-manifest"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["The Extism Authors", "oss@extism.org"]
|
||||
license = "BSD-3-Clause"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { withContext, Context } from "./dist/index.js";
|
||||
import { readFileSync } from "fs";
|
||||
const { withContext, Context } = require('./dist/index.js');
|
||||
const { readFileSync } = require('fs');
|
||||
|
||||
withContext(async function (context) {
|
||||
let wasm = readFileSync("../wasm/code.wasm");
|
||||
4
node/package-lock.json
generated
4
node/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@extism/extism",
|
||||
"version": "0.0.1-rc.6",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@extism/extism",
|
||||
"version": "0.0.1-rc.6",
|
||||
"version": "0.0.1",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"ffi-napi": "^4.0.3"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@extism/extism",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.0",
|
||||
"description": "Extism Host SDK for Node",
|
||||
"keywords": [
|
||||
"extism",
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "npm run build",
|
||||
"example": "node example.mjs",
|
||||
"example": "node example.js",
|
||||
"build": "tsc",
|
||||
"test": "jest --coverage"
|
||||
},
|
||||
|
||||
3
python/README.md
Normal file
3
python/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Extism Python Host SDK
|
||||
|
||||
See [https://extism.org/docs/integrate-into-your-codebase/python-host-sdk/](https://extism.org/docs/integrate-into-your-codebase/python-host-sdk/).
|
||||
@@ -1,10 +1,10 @@
|
||||
[tool.poetry]
|
||||
name = "extism"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0"
|
||||
description = "Extism Host SDK for python"
|
||||
authors = ["The Extism Authors <oss@extism.org>"]
|
||||
license = "BSD-3-Clause"
|
||||
readme = "../README.md"
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
RUBYGEMS_API_KEY ?=
|
||||
|
||||
.PHONY: prepare test
|
||||
|
||||
@@ -9,11 +10,15 @@ test: prepare
|
||||
bundle exec rake test
|
||||
|
||||
clean:
|
||||
rm extism-*.gem
|
||||
rm -f extism-*.gem
|
||||
|
||||
publish-local: clean prepare
|
||||
gem build extism.gemspec
|
||||
gem push extism-*.gem
|
||||
|
||||
publish: clean prepare
|
||||
gem build extism.gemspec
|
||||
gem push extism-*.gem
|
||||
GEM_HOST_API_KEY=$(RUBYGEMS_API_KEY) gem push extism-*.gem
|
||||
|
||||
lint:
|
||||
bundle exec rufo --check .
|
||||
|
||||
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
# Uncomment to register a new dependency of your gem
|
||||
# spec.add_dependency "example-gem", "~> 1.0"
|
||||
spec.add_dependency "ffi", ">= 1.0.0"
|
||||
|
||||
# For more information and examples about making a new gem, check out our
|
||||
# guide at: https://bundler.io/guides/creating_gem.html
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Extism
|
||||
VERSION = "0.0.1"
|
||||
VERSION = "0.1.0"
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "extism-runtime"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["The Extism Authors", "oss@extism.org"]
|
||||
license = "BSD-3-Clause"
|
||||
@@ -22,7 +22,7 @@ log4rs = "1.1"
|
||||
url = "2"
|
||||
glob = "0.3"
|
||||
ureq = {version = "2.5", optional=true}
|
||||
extism-manifest = { version = "0.0.1-rc.6", path = "../manifest" }
|
||||
extism-manifest = { version = "0.1.0", path = "../manifest" }
|
||||
pretty-hex = { version = "0.3" }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "extism"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["The Extism Authors", "oss@extism.org"]
|
||||
license = "BSD-3-Clause"
|
||||
@@ -9,8 +9,8 @@ repository = "https://github.com/extism/extism"
|
||||
description = "Extism Host SDK for Rust"
|
||||
|
||||
[dependencies]
|
||||
extism-manifest = { version = "0.0.1-rc.6", path = "../manifest" }
|
||||
extism-runtime = { version = "0.0.1-rc.6", path = "../runtime"}
|
||||
extism-manifest = { version = "0.1.0", path = "../manifest" }
|
||||
extism-runtime = { version = "0.1.0", path = "../runtime"}
|
||||
serde_json = "1"
|
||||
log = "0.4"
|
||||
thiserror = "1"
|
||||
|
||||
Reference in New Issue
Block a user