From 939b081cac477bf0b7f6fb7d02ac44adc34f1b89 Mon Sep 17 00:00:00 2001 From: Matt Johnson-Pint Date: Wed, 12 Jun 2024 18:12:46 -0700 Subject: [PATCH 1/4] Remove old registration channel and goroutine --- functions/registration.go | 35 +++++++++-------------------------- main.go | 4 ---- wasmhost/loader.go | 5 +++-- wasmhost/wasmhost.go | 3 --- 4 files changed, 12 insertions(+), 35 deletions(-) diff --git a/functions/registration.go b/functions/registration.go index 44d7602d..fead69e8 100644 --- a/functions/registration.go +++ b/functions/registration.go @@ -9,7 +9,6 @@ import ( "hmruntime/logger" "hmruntime/plugins" - "hmruntime/wasmhost" ) var Functions = make(map[string]FunctionInfo) @@ -19,38 +18,22 @@ type FunctionInfo struct { Plugin *plugins.Plugin } -func MonitorRegistration(ctx context.Context) { - go func() { - for { - select { - case <-wasmhost.RegistrationRequest: - r := newRegistration() - r.registerAll(ctx) - r.cleanup(ctx) - case <-ctx.Done(): - return - } - } - }() -} - -type registration struct { - functions map[string]bool - types map[string]bool -} - -func newRegistration() *registration { - return ®istration{ +func RegisterFunctions(ctx context.Context, plugins []plugins.Plugin) { + r := ®istration{ functions: make(map[string]bool), types: make(map[string]bool), } -} -func (r *registration) registerAll(ctx context.Context) { - var plugins = wasmhost.Plugins.GetAll() for _, plugin := range plugins { r.registerPlugin(ctx, &plugin) } + + r.cleanup(ctx) +} + +type registration struct { + functions map[string]bool + types map[string]bool } func (r *registration) registerPlugin(ctx context.Context, plugin *plugins.Plugin) { diff --git a/main.go b/main.go index 4b08f6e1..e456222f 100644 --- a/main.go +++ b/main.go @@ -16,7 +16,6 @@ import ( "hmruntime/aws" "hmruntime/config" "hmruntime/db" - "hmruntime/functions" "hmruntime/graphql" "hmruntime/logger" "hmruntime/manifestdata" @@ -81,9 +80,6 @@ func initRuntimeServices(ctx context.Context) { // Initialize the metadata database db.Initialize(ctx) - // Watch for function registration requests - functions.MonitorRegistration(ctx) - // Load app data and monitor for changes manifestdata.MonitorManifestFile(ctx) diff --git a/wasmhost/loader.go b/wasmhost/loader.go index 1a401c85..dd0ffa21 100644 --- a/wasmhost/loader.go +++ b/wasmhost/loader.go @@ -9,6 +9,7 @@ import ( "fmt" "time" + "hmruntime/functions" "hmruntime/logger" "hmruntime/plugins" "hmruntime/storage" @@ -49,8 +50,8 @@ func MonitorPlugins(ctx context.Context) { } sm.Changed = func(errors []error) { if len(errors) == 0 { - // Signal that we need to register functions - RegistrationRequest <- true + plugins := Plugins.GetAll() + functions.RegisterFunctions(ctx, plugins) } } sm.Start(ctx) diff --git a/wasmhost/wasmhost.go b/wasmhost/wasmhost.go index 21d85cfd..7491762b 100644 --- a/wasmhost/wasmhost.go +++ b/wasmhost/wasmhost.go @@ -23,9 +23,6 @@ import ( // Global runtime instance for the WASM modules var RuntimeInstance wazero.Runtime -// Channel used to signal that registration is needed -var RegistrationRequest chan bool = make(chan bool) - // Global, thread-safe registry of all plugins loaded by the host var Plugins = plugins.NewPluginRegistry() From 1715ab06a88f790df01c03f546210b1fb9400f00 Mon Sep 17 00:00:00 2001 From: Matt Johnson-Pint Date: Wed, 12 Jun 2024 18:51:10 -0700 Subject: [PATCH 2/4] Add helpers --- hostfunctions/helpers.go | 38 +++++++++++++++++++++++++++++ hostfunctions/helpers_test.go | 46 +++++++++++++++++++++++++++++++++++ plugins/plugins.go | 32 ++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 hostfunctions/helpers_test.go diff --git a/hostfunctions/helpers.go b/hostfunctions/helpers.go index b04f2a48..795bcee4 100644 --- a/hostfunctions/helpers.go +++ b/hostfunctions/helpers.go @@ -7,7 +7,10 @@ package hostfunctions import ( "context" "errors" + "fmt" + "strings" + "hmruntime/functions" "hmruntime/functions/assemblyscript" wasm "github.com/tetratelabs/wazero/api" @@ -112,3 +115,38 @@ func readParams4[T1, T2, T3, T4 any](ctx context.Context, mod wasm.Module, // err6 := readParam[T6](ctx, mod, p6, v6) // return errors.Join(err1, err2, err3, err4, err5, err6) // } + +func callFunction(ctx context.Context, mod wasm.Module, fnName string, inputValues ...any) (any, error) { + info, ok := functions.Functions[fnName] + if !ok { + return nil, fmt.Errorf("no function registered named %s", fnName) + } + + parameters := make(map[string]any, len(inputValues)) + for i, value := range inputValues { + name := info.Function.Parameters[i].Name + parameters[name] = value + } + + return functions.CallFunction(ctx, mod, info, parameters) +} + +func verifyFunctionSignature(fnName string, expectedTypes ...string) error { + info, ok := functions.Functions[fnName] + if !ok { + return fmt.Errorf("no function registered named %s", fnName) + } + + if len(expectedTypes) == 0 { + return errors.New("expectedTypes must not be empty") + } + l := len(expectedTypes) + expectedSig := fmt.Sprintf("(%s):%s", strings.Join(expectedTypes[:l-1], ","), expectedTypes[l-1]) + + sig := info.Function.Signature() + if sig != expectedSig { + return fmt.Errorf("function %s has signature %s, expected %s", fnName, sig, expectedSig) + } + + return nil +} diff --git a/hostfunctions/helpers_test.go b/hostfunctions/helpers_test.go new file mode 100644 index 00000000..74086130 --- /dev/null +++ b/hostfunctions/helpers_test.go @@ -0,0 +1,46 @@ +/* + * Copyright 2024 Hypermode, Inc. + */ + +package hostfunctions + +import ( + "hmruntime/functions" + "hmruntime/plugins" + "testing" +) + +func Test_VerifyFunctionSignature(t *testing.T) { + + functions.Functions["myFunction"] = functions.FunctionInfo{ + Function: plugins.FunctionSignature{ + Name: "myFunction", + Parameters: []plugins.Parameter{ + {Name: "param1", Type: plugins.TypeInfo{Name: "int"}}, + {Name: "param2", Type: plugins.TypeInfo{Name: "string"}}, + }, + ReturnType: plugins.TypeInfo{Name: "bool"}, + }} + + err := verifyFunctionSignature("myFunction", "int", "string", "bool") + if err != nil { + t.Errorf("verifyFunctionSignature failed: %v", err) + } + + functions.Functions["anotherFunction"] = functions.FunctionInfo{ + Function: plugins.FunctionSignature{ + Name: "anotherFunction", + ReturnType: plugins.TypeInfo{Name: "bool"}, + }, + } + + err = verifyFunctionSignature("anotherFunction", "bool") + if err != nil { + t.Errorf("verifyFunctionSignature failed: %v", err) + } + + err = verifyFunctionSignature("nonExistentFunction", "float64") + if err == nil { + t.Error("verifyFunctionSignature should have returned an error for non-existent function") + } +} diff --git a/plugins/plugins.go b/plugins/plugins.go index 00e0fd68..e5f02213 100644 --- a/plugins/plugins.go +++ b/plugins/plugins.go @@ -7,6 +7,7 @@ package plugins import ( "context" "fmt" + "strings" "time" "hmruntime/utils" @@ -38,6 +39,37 @@ type FunctionSignature struct { ReturnType TypeInfo `json:"returnType"` } +func (f *FunctionSignature) String() string { + b := strings.Builder{} + b.WriteString(f.Name) + b.WriteString("(") + for i, p := range f.Parameters { + if i > 0 { + b.WriteString(", ") + } + b.WriteString(p.Name) + b.WriteString(": ") + b.WriteString(p.Type.Name) + } + b.WriteString("): ") + b.WriteString(f.ReturnType.Name) + return b.String() +} + +func (f *FunctionSignature) Signature() string { + b := strings.Builder{} + b.WriteString("(") + for i, p := range f.Parameters { + if i > 0 { + b.WriteString(",") + } + b.WriteString(p.Type.Name) + } + b.WriteString("):") + b.WriteString(f.ReturnType.Name) + return b.String() +} + type TypeDefinition struct { Id uint32 `json:"id"` Size uint32 `json:"size"` From 987dcf064c7615d9955660370e24df74e53f0f84 Mon Sep 17 00:00:00 2001 From: Matt Johnson-Pint Date: Wed, 12 Jun 2024 18:52:20 -0700 Subject: [PATCH 3/4] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7b91e50..f29374e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Lowercase model name before invoking for hypermode hosted models [#221](https://github.com/gohypermode/runtime/pull/221) - Improve HTTP error messages [#222](https://github.com/gohypermode/runtime/pull/222) - Add host function for direct logging [#224](https://github.com/gohypermode/runtime/pull/224) +- Refactoring, and add helpers for calling functions [#226](https://github.com/gohypermode/runtime/pull/226) ## 2024-06-03 - Version 0.8.2 From c8cc0f360d82ad787d2737070028d3dcfe4dbc9f Mon Sep 17 00:00:00 2001 From: Matt Johnson-Pint Date: Wed, 12 Jun 2024 18:59:46 -0700 Subject: [PATCH 4/4] fix linter --- hostfunctions/helpers.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hostfunctions/helpers.go b/hostfunctions/helpers.go index 795bcee4..79c419e7 100644 --- a/hostfunctions/helpers.go +++ b/hostfunctions/helpers.go @@ -116,6 +116,8 @@ func readParams4[T1, T2, T3, T4 any](ctx context.Context, mod wasm.Module, // return errors.Join(err1, err2, err3, err4, err5, err6) // } +var _ = callFunction // @jairad26 - remove this plz + func callFunction(ctx context.Context, mod wasm.Module, fnName string, inputValues ...any) (any, error) { info, ok := functions.Functions[fnName] if !ok {