Skip to content

Commit

Permalink
fix: create separate closure for each host function (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhmd-azeez authored Aug 6, 2023
1 parent 8b0bc35 commit 5f8df6d
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 2 deletions.
85 changes: 85 additions & 0 deletions extism_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,91 @@ func TestHost_memory(t *testing.T) {
}
}

func TestHost_multiple(t *testing.T) {
manifest := manifest("host_multiple.wasm")

config := PluginConfig{
ModuleConfig: wazero.NewModuleConfig().WithSysWalltime(),
EnableWasi: true,
}

green_message := HostFunction{
Name: "hostGreenMessage",
Namespace: "env",
Callback: func(ctx context.Context, plugin *CurrentPlugin, userData interface{}, stack []uint64) {
offset := stack[0]
input, err := plugin.ReadString(offset)

if err != nil {
fmt.Println("🥵", err.Error())
panic(err)
}

message := "🟢:" + string(input)
offset, err = plugin.WriteString(message)

if err != nil {
fmt.Println("🥵", err.Error())
panic(err)
}

stack[0] = offset
},
Params: []api.ValueType{api.ValueTypeI64},
Results: []api.ValueType{api.ValueTypeI64},
}

purple_message := HostFunction{
Name: "hostPurpleMessage",
Namespace: "env",
Callback: func(ctx context.Context, plugin *CurrentPlugin, userData interface{}, stack []uint64) {
offset := stack[0]
input, err := plugin.ReadString(offset)

if err != nil {
fmt.Println("🥵", err.Error())
panic(err)
}

message := "🟣:" + string(input)
offset, err = plugin.WriteString(message)

if err != nil {
fmt.Println("🥵", err.Error())
panic(err)
}

stack[0] = offset
},
Params: []api.ValueType{api.ValueTypeI64},
Results: []api.ValueType{api.ValueTypeI64},
}

hostFunctions := []HostFunction{
purple_message,
green_message,
}

ctx := context.Background()
pluginInst, err := NewPlugin(ctx, manifest, config, hostFunctions)

if err != nil {
panic(err)
}

_, res, err := pluginInst.Call(
"say_green",
[]byte("John Doe"),
)
assert.Equal(t, "🟢:🫱 Hey from say_green John Doe", string(res))

_, res, err = pluginInst.Call(
"say_purple",
[]byte("Jane Doe"),
)
assert.Equal(t, "🟣:👋 Hello from say_purple Jane Doe", string(res))
}

func TestHTTP_allowed(t *testing.T) {
manifest := manifest("http.wasm")
manifest.AllowedHosts = []string{"jsonplaceholder.*.com"}
Expand Down
12 changes: 10 additions & 2 deletions host.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,22 @@ func buildHostModule(ctx context.Context, rt wazero.Runtime, name string, funcs

func defineCustomHostFunctions(builder wazero.HostModuleBuilder, funcs []HostFunction) {
for _, f := range funcs {

// Go closures capture variables by reference, not by value.
// This means that if you directly use f inside the closure without creating
// a separate variable (closure) and assigning the value of f to it, you might run into unexpected behavior.
// All the closures created in the loop would end up referencing the same f, which could lead to incorrect or unintended results.
// See: https://github.com/extism/go-sdk/issues/5#issuecomment-1666774486
closure := f

builder.NewFunctionBuilder().WithGoFunction(api.GoFunc(func(ctx context.Context, stack []uint64) {
if plugin, ok := ctx.Value("plugin").(*Plugin); ok {
f.Callback(ctx, &CurrentPlugin{plugin}, f.UserData, stack)
closure.Callback(ctx, &CurrentPlugin{plugin}, closure.UserData, stack)
return
}

panic("Invalid context, `plugin` key not found")
}), f.Params, f.Results).Export(f.Name)
}), closure.Params, closure.Results).Export(closure.Name)
}
}

Expand Down
8 changes: 8 additions & 0 deletions plugins/host_multiple/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/extism/extism-sdk-plugins-host-multiple

go 1.20

require (
github.com/extism/go-pdk v0.0.0-20230119214914-65bffbeb3e64 // indirect
github.com/valyala/fastjson v1.6.3 // indirect
)
4 changes: 4 additions & 0 deletions plugins/host_multiple/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/extism/go-pdk v0.0.0-20230119214914-65bffbeb3e64 h1:IfR1k741q+yQLvv5sLShCkvt3FgKU4wQVJfp7hhb/iY=
github.com/extism/go-pdk v0.0.0-20230119214914-65bffbeb3e64/go.mod h1:1wdiAoG8306g4WK+6laBrS+75089/0V4XRVTllt8b5U=
github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc=
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
48 changes: 48 additions & 0 deletions plugins/host_multiple/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package main

import (
"github.com/extism/go-pdk"
)

//export hostPurpleMessage
func hostPurpleMessage(offset uint64) uint64

func purpleMessage(message string) pdk.Memory {
messageMemory := pdk.AllocateString(message)
off := hostPurpleMessage(messageMemory.Offset())
return pdk.FindMemory(off)
}

//export hostGreenMessage
func hostGreenMessage(offset uint64) uint64

func greenMessage(message string) pdk.Memory {
messageMemory := pdk.AllocateString(message)
off := hostGreenMessage(messageMemory.Offset())
return pdk.FindMemory(off)
}

//export say_purple
func say_purple() int32 {
input := pdk.InputString()
output := "👋 Hello from say_purple " + input

mem := purpleMessage(output)

pdk.OutputMemory(mem)
return 0

}

//export say_green
func say_green() int32 {
input := pdk.Input()
output := "🫱 Hey from say_green " + string(input)

mem := greenMessage(output)

pdk.OutputMemory(mem)
return 0

}
func main() {}
Binary file added wasm/host_multiple.wasm
Binary file not shown.

0 comments on commit 5f8df6d

Please sign in to comment.