PLUGINS 1g 2023-07-13 laplante@plcb.ca GOWEB/language

Description

Plugins are use to implement new functions in GO to be use by goweb. The module need to be implemented as a main module using goweb/vm module. The Makefile to compile the plugin can be:

example: *.go 
	go build -buildmode=plugin
	install example.so /usr/local/lib

test:
	go test -v

To use the module you can modify the toml configuation file as in:

[description]
	plugin = [ "example"]

[example]
    file="/usr/local/lib/example.so"
	init="Register_function"

The init parameter define the function that we be use to define all functions:

package main

import (
	"goweb/vm"
	"log"
)

func Register_function(v *vm.Vm) {
	v.Listfunc["example"] = goweb_example
}

func goweb_plugin_example(v *vm.Vm, nbelem int) error {
	// scan arguments
	var file string
	var errid string
	var err error
	generr := false

	for i := 0; i < nbelem; i++ {
		d := v.Stack[v.Sp-(nbelem-i)]
		if d.Data_type == vm.Type_id {
			v, _, err := vm.Get_id(v, d.Id)
			if err != nil {
				return fmt.Errorf("plugin::example : id is not defined: %!s(MISSING)", d.Id)
			}
			d = v
		} else if d.Data_type == vm.Type_nargs {
			nargs := d.Nargs
			i++
			next := v.Stack[v.Sp-(nbelem-i)]
			switch nargs {

			case "error":
				if next.Data_type != vm.Type_id {
					return fmt.Errorf("plugin::example : invalid id for parameter %!s(MISSING): %!s(MISSING)", nargs, vm.Type_text[next.Data_type])
				}
				errid = next.Id
				vm.New_id(v, errid, vm.Data_value{})
			case "generr":
				generr = true
			default:
				return fmt.Errorf("plugin::example : id is not defined: %!s(MISSING)", d.Id)
			}
		} else {
			if file != "" {
				return fmt.Errorf("plugin::example : only 1 file can be use")
			}
			file, err = vm.Get_sval(v, d)
			if err != nil {
				return fmt.Errorf("plugin::example : parameter 1 can't be a string")
			}
		}
	}

	// remove argument from stack
	v.Sp -= nbelem

	if generr {
		err := vm.Errorid(v, errid, "an error has been requested: id=%!s(MISSING)", errid)
		if err != nil {
			return err
		}
	}

	// Push element on stack
	data_value := vm.Data_value{
		Data_type: vm.Type_string,
		Sval:      "example",
	}

	v.Stack[v.Sp] = data_value
	v.Sp++
	return nil

Version

PLUGINS 1g 2023-07-13 laplante@plcb.ca GOWEB/Language


title: “PLUGINS” author: “Pierre Laplante laplante@plcb.ca” date: “2023-07-13” version: “1.0” section: “1g”

category: “GOWEB/Language”

Description

Plugins are used to implement new functions in Go that can be executed within goweb.
A plugin must be implemented as a main module using the goweb/vm package.

Example Makefile

example: *.go 
	go build -buildmode=plugin
	install example.so /usr/local/lib

test:
	go test -v

Configuration

To use a plugin, update the TOML configuration file:

[description]
plugin = [ "example" ]

[example]
file="/usr/local/lib/example.so"
init="Register_function"

The init parameter specifies the function that will be invoked to register all plugin-defined functions.

Example Plugin Implementation

package main

import (
	"goweb/vm"
	"log"
)

func Register_function(v *vm.Vm) {
	v.Listfunc["example"] = goweb_example
}

func goweb_plugin_example(v *vm.Vm, nbelem int) error {
	// scan arguments
	var file string
	var errid string
	var err error
	generr := false

	for i := 0; i < nbelem; i++ {
		d := v.Stack[v.Sp-(nbelem-i)]
		if d.Data_type == vm.Type_id {
			v, _, err := vm.Get_id(v, d.Id)
			if err != nil {
				return fmt.Errorf("plugin::example : id is not defined: %!s(MISSING)", d.Id)
			}
			d = v
		} else if d.Data_type == vm.Type_nargs {
			nargs := d.Nargs
			i++
			next := v.Stack[v.Sp-(nbelem-i)]
			switch nargs {
			case "error":
				if next.Data_type != vm.Type_id {
					return fmt.Errorf("plugin::example : invalid id for parameter %!s(MISSING): %!s(MISSING)", nargs, vm.Type_text[next.Data_type])
				}
				errid = next.Id
				vm.New_id(v, errid, vm.Data_value{})
			case "generr":
				generr = true
			default:
				return fmt.Errorf("plugin::example : invalid parameter: %!s(MISSING)", d.Id)
			}
		} else {
			if file != "" {
				return fmt.Errorf("plugin::example : only one file can be specified")
			}
			file, err = vm.Get_sval(v, d)
			if err != nil {
				return fmt.Errorf("plugin::example : parameter must be a string")
			}
		}
	}

	// remove arguments from stack
	v.Sp -= nbelem

	if generr {
		err := vm.Errorid(v, errid, "an error has been requested: id=%!s(MISSING)", errid)
		if err != nil {
			return err
		}
	}

	// push element on stack
	data_value := vm.Data_value{
		Data_type: vm.Type_string,
		Sval:      "example",
	}

	v.Stack[v.Sp] = data_value
	v.Sp++
	return nil
}

Version