From 33b1e36189a10e27c2ccfddaac383907d54e31d1 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Wed, 17 Jan 2024 12:58:45 -0700 Subject: [PATCH] feat: remove strings dependency, optimizations (#23) --- .github/workflows/ci.yml | 4 ++ Makefile | 8 +-- example/countvowels/std_main.go | 49 ++++++++++++++++++ example/countvowels/{main.go => tiny_main.go} | 3 ++ example/http/std_main.go | 29 +++++++++++ example/http/{main.go => tiny_main.go} | 5 +- extism_pdk.go | 50 +++++++++++++++++-- 7 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 example/countvowels/std_main.go rename example/countvowels/{main.go => tiny_main.go} (95%) create mode 100644 example/http/std_main.go rename example/http/{main.go => tiny_main.go} (78%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 618aba2..ce755d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,3 +47,7 @@ jobs: echo $TEST | grep '"a": "this is var a"' extism call example/tiny_http.wasm --wasi http_get --github-token="$GITHUB_TOKEN" --allow-host "jsonplaceholder.typicode.com" | grep '"userId": 1' + + + # run all the tests + make test diff --git a/Makefile b/Makefile index 103c1bc..31fcaeb 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,12 @@ example: tinygo build -o example/tiny_countvowels.wasm -target wasi ./example/countvowels tinygo build -o example/tiny_http.wasm -target wasi ./example/http - GOOS=wasip1 GOARCH=wasm go build -o example/std_countvowels.wasm ./example/countvowels - GOOS=wasip1 GOARCH=wasm go build -o example/std_http.wasm ./example/http + GOOS=wasip1 GOARCH=wasm go build -tags std -o example/std_countvowels.wasm ./example/countvowels + GOOS=wasip1 GOARCH=wasm go build -tags std -o example/std_http.wasm ./example/http test: extism call example/tiny_countvowels.wasm count_vowels --wasi --input "this is a test" --set-config '{"thing": "1234"}' extism call example/tiny_http.wasm http_get --wasi --log-level info --allow-host "jsonplaceholder.typicode.com" - extism call example/std_countvowels.wasm count_vowels --wasi --input "this is a test" --set-config '{"thing": "1234"}' - extism call example/std_http.wasm http_get --wasi --log-level info --allow-host "jsonplaceholder.typicode.com" \ No newline at end of file + extism call example/std_countvowels.wasm _start --wasi --input "this is a test" --set-config '{"thing": "1234"}' + extism call example/std_http.wasm _start --wasi --log-level info --allow-host "jsonplaceholder.typicode.com" \ No newline at end of file diff --git a/example/countvowels/std_main.go b/example/countvowels/std_main.go new file mode 100644 index 0000000..f371206 --- /dev/null +++ b/example/countvowels/std_main.go @@ -0,0 +1,49 @@ +//go:build std +// +build std + +package main + +import ( + "strconv" + + "github.com/extism/go-pdk" +) + +// Currently, the standard Go compiler cannot export custom functions and is limited to exporting +// `_start` via WASI. So, `main` functions should contain the plugin behavior, that the host will +// invoke by explicitly calling `_start`. +func main() { + countVowels() +} + +func countVowels() int32 { + input := pdk.Input() + + count := 0 + for _, a := range input { + switch a { + case 'A', 'I', 'E', 'O', 'U', 'a', 'e', 'i', 'o', 'u': + count++ + default: + } + } + + // test some extra pdk functionality + if pdk.GetVar("a") == nil { + pdk.SetVar("a", []byte("this is var a")) + } + varA := pdk.GetVar("a") + thing, ok := pdk.GetConfig("thing") + + if !ok { + thing = "" + } + + output := `{"count": ` + strconv.Itoa(count) + `, "config": "` + thing + `", "a": "` + string(varA) + `"}` + mem := pdk.AllocateString(output) + + // zero-copy output to host + pdk.OutputMemory(mem) + + return 0 +} diff --git a/example/countvowels/main.go b/example/countvowels/tiny_main.go similarity index 95% rename from example/countvowels/main.go rename to example/countvowels/tiny_main.go index 754e570..7b7f9e0 100644 --- a/example/countvowels/main.go +++ b/example/countvowels/tiny_main.go @@ -1,3 +1,6 @@ +//go:build !std +// +build !std + package main import ( diff --git a/example/http/std_main.go b/example/http/std_main.go new file mode 100644 index 0000000..d98e42e --- /dev/null +++ b/example/http/std_main.go @@ -0,0 +1,29 @@ +//go:build std +// +build std + +package main + +import ( + "github.com/extism/go-pdk" +) + +// Currently, the standard Go compiler cannot export custom functions and is limited to exporting +// `_start` via WASI. So, `main` functions should contain the plugin behavior, that the host will +// invoke by explicitly calling `_start`. +func main() { + httpGet() +} + +func httpGet() int32 { + // create an HTTP Request (withuot relying on WASI), set headers as needed + req := pdk.NewHTTPRequest(pdk.MethodGet, "https://jsonplaceholder.typicode.com/todos/1") + req.SetHeader("some-name", "some-value") + req.SetHeader("another", "again") + // send the request, get response back (can check status on response via res.Status()) + res := req.Send() + + // zero-copy output to host + pdk.OutputMemory(res.Memory()) + + return 0 +} diff --git a/example/http/main.go b/example/http/tiny_main.go similarity index 78% rename from example/http/main.go rename to example/http/tiny_main.go index 4035d20..cd828e6 100644 --- a/example/http/main.go +++ b/example/http/tiny_main.go @@ -1,3 +1,6 @@ +//go:build !std +// +build !std + package main import ( @@ -7,7 +10,7 @@ import ( //export http_get func httpGet() int32 { // create an HTTP Request (withuot relying on WASI), set headers as needed - req := pdk.NewHTTPRequest("GET", "https://jsonplaceholder.typicode.com/todos/1") + req := pdk.NewHTTPRequest(pdk.MethodGet, "https://jsonplaceholder.typicode.com/todos/1") req.SetHeader("some-name", "some-value") req.SetHeader("another", "again") // send the request, get response back (can check status on response via res.Status()) diff --git a/extism_pdk.go b/extism_pdk.go index 453ecb1..291acfb 100644 --- a/extism_pdk.go +++ b/extism_pdk.go @@ -3,7 +3,6 @@ package pdk import ( "encoding/binary" "encoding/json" - "strings" ) type Memory struct { @@ -258,13 +257,54 @@ func (r HTTPResponse) Status() uint16 { return r.status } -func NewHTTPRequest(method string, url string) *HTTPRequest { +type HTTPMethod int32 + +const ( + MethodGet HTTPMethod = iota + MethodHead + MethodPost + MethodPut + MethodPatch // RFC 5789 + MethodDelete + MethodConnect + MethodOptions + MethodTrace +) + +func (m HTTPMethod) String() string { + switch m { + case MethodGet: + return "GET" + case MethodHead: + return "HEAD" + case MethodPost: + return "POST" + case MethodPut: + return "PUT" + case MethodPatch: + return "PATCH" + case MethodDelete: + return "DELETE" + case MethodConnect: + return "CONNECT" + case MethodOptions: + return "OPTIONS" + case MethodTrace: + return "TRACE" + default: + return "" + } +} + +func NewHTTPRequest(method HTTPMethod, url string) *HTTPRequest { return &HTTPRequest{ meta: HTTPRequestMeta{ - Url: url, - Method: strings.ToUpper(method), + Url: url, + Headers: nil, + Method: method.String(), }, - body: nil} + body: nil, + } } func (r *HTTPRequest) SetHeader(key string, value string) *HTTPRequest {