Run Extism WebAssembly plugins from a Go application
For a few days, we have seen that it is possible to develop WebAssembly plugins with the Extism Plugin Development Kit and run them with the Extism CLI. Today, it's time to move up a level: we will create an application in Go that can load and run these plugins as the CLI does.
We will use the Host SDK of Extism for the Go language to do this. As a reminder, Extism provides Host SDKs for many languages (https://extism.org/docs/category/integrate-into-your-codebase).
As a reminder, a host application is an application that, thanks to a Wasm runtime SDK, can run WebAssembly programs. The Host SDKs of Extism are "overlays" on the Wasm runtime SDK to make your life easier (avoid complicated plumbing).
Currently, Extism uses the WasmTime runtime.
If I refer to this issue (WASI threads support), the support of other Wasm runtimes may be taken into account and in particular Wazero.
But enough talk; let's get down to business.
Prerequisites
You will need
Go (v1.20)
Extism 0.4.0: Install Extism
✋ Pay attention (Mon 7 Aug 2023)
The Extism Go SDK on top of Wazero. Now, the SDK is purely written in Go (no more dependency on cgo 🎉). However, the new SDK is not released yet. So to be able to use it and build your projects, you must:
clone the new repository:
git clone
git@github.com
:extism/go-sdk.git
add a local reference of this git repository into the
go.mod
file of your projects:replace
github.com/extism/extism
=> ../go-sdk
https://twitter.com/mhmd_azeez/status/1688198055986622464
Creating the application
Start by creating a go.mod
file with the command go mod init go-host-application
, then a main.go
file with the following content:
package main
import (
"context"
"fmt"
"github.com/extism/extism"
"github.com/tetratelabs/wazero"
)
func main() {
ctx := context.Background()
// Define config, path to the wasm file
// and manifest 0️⃣
config := extism.PluginConfig{
ModuleConfig: wazero.NewModuleConfig().WithSysWalltime(),
EnableWasi: true,
}
️
path := "../03-even-with-javascript/hello-js.wasm"
// Define the path to the wasm file 1️⃣
manifest := extism.Manifest{
Wasm: []extism.Wasm{
extism.WasmFile{
Path: path},
}}
// Load the wasm plugin 2️⃣
pluginInst, err := extism.NewPlugin(ctx, manifest, config, nil)
if err != nil {
panic(err)
}
// Call the `say_hello` function 3️⃣
// with a string parameter
_, res, err := pluginInst.Call(
"say_hello",
[]byte("👋 Hello from the Go Host app 🤗"),
)
if err != nil {
fmt.Println("😡", err)
} else {
// Display the return value 4️⃣
fmt.Println("🙂", string(res))
}
}
You see, the code is straightforward:
0: let's use the JavaScript Wasm plugin we developed in the previous article.
1: define a manifest with properties, including the Wasm file path.
2: load the Wasm plugin.
3: call the
say_hello
function of the plugin.4: display the result (the type of
res
is[]byte
).
Run the program
Use simply this command:
go run main.go
And you will get this:
🙂 param: 👋 Hello from the Go Host app 🤗
You can do the test with the first plugin developed with TinyGo. Change the value of the variable path := "../01-simple-go-plugin/simple.wasm"
and run again:
go run main.go
And you should get this:
🙂 👋 Hello 👋 Hello from the Go Host app 🤗
🎉 you see, creating Go applications that run Wasm plugins written in different languages is easy.
If I can keep up the pace, tomorrow I'll explain how to do the same thing but this time with Node.js.
Subscribe to my newsletter
Read articles from Philippe Charrière directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by