diff --git a/config.go b/config.go index 12fdeb73..d66d2d68 100644 --- a/config.go +++ b/config.go @@ -23,6 +23,7 @@ import ( "regexp" interfaces "github.com/loopholelabs/scale-signature-interfaces" + "github.com/loopholelabs/scale/extension" "github.com/loopholelabs/scale/scalefunc" ) @@ -49,6 +50,8 @@ type Config[T interfaces.Signature] struct { context context.Context Stdout io.Writer Stderr io.Writer + + extensions map[string]extension.InstallableFunc } // NewConfig returns a new Scale Runtime Config @@ -84,6 +87,17 @@ func (c *Config[T]) validate() error { return nil } +func (c *Config[T]) WithExtensions(e map[string]extension.InstallableFunc) *Config[T] { + if c.extensions == nil { + c.extensions = make(map[string]extension.InstallableFunc) + } + for n, f := range e { + // TODO: Check for stomping etc + c.extensions[n] = f + } + return c +} + func (c *Config[T]) WithSignature(newSignature interfaces.New[T]) *Config[T] { c.newSignature = newSignature return c diff --git a/extension/generator/templates/guest.go.templ b/extension/generator/templates/guest.go.templ index e0c18c9f..13728c98 100644 --- a/extension/generator/templates/guest.go.templ +++ b/extension/generator/templates/guest.go.templ @@ -87,7 +87,7 @@ func ext_{{ $schema.Name }}_{{ $ifc.Name }}_{{ $fn.Name }}(instance uint64, offs //export ext_{{ $schema.Name }}_{{ $fn.Name }} //go:linkname ext_{{ $schema.Name }}_{{ $fn.Name }} -func ext_{{ $schema.Name }}_{{ $fn.Name }}(offset uint32, length uint32) uint64 +func ext_{{ $schema.Name }}_{{ $fn.Name }}(instance uint64, offset uint32, length uint32) uint64 func {{ $fn.Name }}(params *{{ $fn.Params }}) ({{ $fn.Return }}, error) { // First we take the params, serialize them. @@ -102,7 +102,7 @@ func {{ $fn.Name }}(params *{{ $fn.Params }}) ({{ $fn.Return }}, error) { // Now make the call to the host. {{- if (IsInterface $schema $fn.Return) }} - v := ext_{{ $schema.Name }}_{{ $fn.Name }}(off, l) + v := ext_{{ $schema.Name }}_{{ $fn.Name }}(0, off, l) // IF the return type is an interface return ifc, which contains hidden instanceId. // TODO: Handle error from host. In this case there'll be an error in the readBuffer @@ -113,7 +113,7 @@ func {{ $fn.Name }}(params *{{ $fn.Params }}) ({{ $fn.Return }}, error) { return ret, nil {{ else }} - ext_{{ $schema.Name }}_{{ $fn.Name }}(off, l) + ext_{{ $schema.Name }}_{{ $fn.Name }}(0, off, l) // IF the return type is a model, we should read the data from the read buffer. ret := &{{ $fn.Return }}{} diff --git a/scale.go b/scale.go index 0ca8d7c3..6e5262fb 100644 --- a/scale.go +++ b/scale.go @@ -28,6 +28,8 @@ import ( "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" "github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1" + + "github.com/loopholelabs/scale/extension" ) // Next is the next function in the middleware chain. It's meant to be implemented @@ -82,7 +84,29 @@ func (r *Scale[T]) init() error { r.moduleConfig = r.moduleConfig.WithStderr(r.config.Stderr) } - envHostModuleBuilder := r.runtime.NewHostModuleBuilder("env"). + envModule := r.runtime.NewHostModuleBuilder("env") + + // Install any extensions... + for name, fn := range r.config.extensions { + fmt.Printf("Installing module [%s]\n", name) + wfn := func(n string, f extension.InstallableFunc) func(context.Context, api.Module, []uint64) { + return func(ctx context.Context, mod api.Module, params []uint64) { + fmt.Printf("HOST FUNCTION CALLED %s\n", n) + mem := mod.Memory() + resize := func(name string, size uint64) (uint64, error) { + w, err := mod.ExportedFunction(name).Call(context.Background(), size) + return w[0], err + } + f(mem, resize, params) + } + }(name, fn) + + envModule.NewFunctionBuilder(). + WithGoModuleFunction(api.GoModuleFunc(wfn), []api.ValueType{api.ValueTypeI64, api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{api.ValueTypeI64}). + WithParameterNames("instance", "pointer", "length").Export(name) + } + + envHostModuleBuilder := envModule. NewFunctionBuilder(). WithGoModuleFunction(api.GoModuleFunc(r.next), []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{}). WithParameterNames("pointer", "length").Export("next") diff --git a/storage/extension.go b/storage/extension.go index f72ad14a..9771c5ef 100644 --- a/storage/extension.go +++ b/storage/extension.go @@ -320,7 +320,10 @@ func GenerateExtension(ext *extension.Schema, name string, tag string, org strin } hostPackage, err := generator.GenerateHostLocal(&generator.Options{ - Extension: ext, + Extension: ext, + GolangPackageImportPath: "extension", + GolangPackageName: ext.Name, + GolangPackageVersion: "v0.1.0", }) if err != nil { return err