pdk

package
v1.2.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 10, 2025 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package pdk provides the Plugin Development Kit for creating WASM plugins compatible with Hookr.

The PDK package contains the necessary tools and utilities for developers to build WASM plugins that can be loaded and executed by Hookr host applications. It handles the communication between the plugin and the host, providing a simple and type-safe API.

Creating a Plugin

To create a plugin, you need to register your functions and export the initialization function:

package main

import (
	"github.com/mopeyjellyfish/hookr/pdk"
)

//go:wasmexport hookr_init
func Initialize() {
	// Register your functions
	pdk.Fn("hello", Hello)
	pdk.Fn("echo", Echo)
}

// Hello is a simple function that returns a greeting
func Hello(input *HelloRequest) (*HelloResponse, error) {
	return &HelloResponse{
		Message: "Hello, " + input.Name + "!",
	}, nil
}

// Echo returns the input as output
func Echo(input *EchoRequest) (*EchoResponse, error) {
	return &EchoResponse{
		Data: input.Data,
	}, nil
}

API

Host's are able to send data to a WASM plugin and a WASM plugin is able to send data back to the host. We use the msgp package to serialize and deserialize data between the host and the plugin.

1. Write your plugin structs in standard Go types. 2. Use the `//go:generate msgp` directive to generate the serialization code. 3. Use the structs as input and output types for your plugin functions. 4. Register your functions with the `pdk.Fn` function. 5. Implement the plugin functions to handle the input and return the output. 6. On the host side, you will also make use of the same API package for the inputs and outputs for both host functions and also for calling plugin functions.

Function Signatures

Plugin functions must follow this pattern:

func YourFunction(input InputType) (OutputType, error)

Where InputType and OutputType implement the msgp.Unmarshaler and msgp.Marshaler interfaces respectively. The easiest way is to use structs with msgp tags:

//go:generate msgp

type HelloRequest struct {
	Name string `msg:"name"`
}

type HelloResponse struct {
	Message string `msg:"message"`
}

Calling Host Functions

Plugins can call back into the host using the HostFn function:

var GreetHost = pdk.HostFn[*GreetRequest, *GreetResponse]("greet")

func Hello(input *HelloRequest) (*HelloResponse, error) {
	// Call the host
	resp, err := GreetHost.Call(&GreetRequest{
		Name: input.Name,
	})
	if err != nil {
		return nil, err
	}

	return &HelloResponse{
		Message: resp.Greeting,
	}, nil
}

Logging

The PDK provides a logging function that sends messages to the host:

func Hello(input *HelloRequest) (*HelloResponse, error) {
	pdk.Log("Received hello request for: " + input.Name)

	// Function logic...

	return &HelloResponse{
		Message: "Hello, " + input.Name + "!",
	}, nil
}

Error Handling

Errors returned from plugin functions are properly propagated to the host:

func Divide(input *DivideRequest) (*DivideResponse, error) {
	if input.Divisor == 0 {
		return nil, fmt.Errorf("division by zero")
	}

	return &DivideResponse{
		Result: input.Dividend / input.Divisor,
	}, nil
}

Building Plugins

To build a plugin for use with Hookr, you typically use TinyGo:

tinygo build -o plugin.wasm -scheduler=none --no-debug -target=wasi main.go

This produces a WebAssembly module that can be loaded by a Hookr host application.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Call

func Call[In Marshaler, Out Unmarshaler](operation string, input In) (Out, error)

func FnByte

func FnByte(name string, fn Function)

FnByte adds a single function by name to the registry. This should be invoked in your initialize func to expose any functions you wish the host to use.

func FnSerial

func FnSerial[In Unmarshaler, Out Marshaler](name string, fn PluginFunction[In, Out])

FnSerial adds a single function by name to the registry. This will invoke the Marshal and Unmarshal functions on the input and output types. This should be invoked in your initialize func to expose any functions you wish the host to use.

func HostCall

func HostCall(operation string, payload []byte) ([]byte, error)

HostCall invokes an operation on the host. The host uses `operation` to route to the `payload` to the appropriate operation. The host will return a response payload if successful.

func Log

func Log(message string)

Log is a convenience function to log messages to the console. It is a wrapper around the `__log` function. The message is passed as a string pointer and length to the host. If the message is empty, it will not log anything.

Types

type Function

type Function func(input []byte) ([]byte, error)

Function is a function that takes a byte slice as input and returns a byte slice as output. This is the function that is called by the host. It is a wrapper around the PluginFunction to allow for byte-based communication.

type Functions

type Functions map[string]Function

Functions is a map of function names to their corresponding Function implementations. This is the registry of functions that are callable by the host. The key is the function name and the value is the Function implementation.

type HostError

type HostError struct {
	// contains filtered or unexported fields
}

func (*HostError) Error

func (e *HostError) Error() string

type HostFunctionByte

type HostFunctionByte struct {
	// contains filtered or unexported fields
}

func HostFnByte

func HostFnByte(name string) *HostFunctionByte

func (*HostFunctionByte) Call

func (h *HostFunctionByte) Call(input []byte) ([]byte, error)

type HostFunctionSerial

type HostFunctionSerial[In Marshaler, Out Unmarshaler] struct {
	// contains filtered or unexported fields
}

func HostFnSerial

func HostFnSerial[In Marshaler, Out Unmarshaler](name string) *HostFunctionSerial[In, Out]

func (*HostFunctionSerial[In, Out]) Call

func (h *HostFunctionSerial[In, Out]) Call(input In) (Out, error)

type Marshaler

type Marshaler interface {
	MarshalMsg([]byte) ([]byte, error)
}

type PluginFunction

type PluginFunction[In Unmarshaler, Out Marshaler] func(input In) (Out, error)

PluginFunction is a function that takes an input of type In and returns an output of type Out. These are the concrete functions that are callable by the host.

type Unmarshaler

type Unmarshaler interface {
	UnmarshalMsg([]byte) ([]byte, error)
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL