pluggable

package module
v0.0.0-...-7710299 Latest Latest
Warning

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

Go to latest
Published: Jan 26, 2023 License: Apache-2.0 Imports: 11 Imported by: 18

README ΒΆ

🍱 go-pluggable

PkgGoDev Go Report Card Test

🍱 go-pluggable is a light Bus-event driven plugin library for Golang.

go-pluggable implements the event/sub pattern to extend your Golang project with external binary plugins that can be written in any language.

import "github.com/mudler/go-pluggable"


func main() {

    var myEv pluggableEventType = "something.to.hook.on"
    temp := "/usr/custom/bin"

    m = pluggable.NewManager(
        []pluggable.EventType{
            myEv,
        },
    )
        
    // Load plugins
    m.Autoload("test", temp) // Scan for binary plugins with the "test" prefix. E.g. 'test-foo'
    m.Plugin = append(m.Plugin, pluggable.Plugin{ Name: "foo" , Executable: "path" }) // manually add a Plugin
    m.Load("my-binary", "my-binary-2"...) // Load individually, scanning $PATH

    // Register to events and initialize the manager
    m.Register()

    // Optionally process plugin results response
    // The plugins has to return as output a json in stdout in the format { 'state': "somestate", data: "some data", error: "some error" }
    // e.g. with jq:  
    // jq --arg key0   'state' \
    // --arg value0 '' \
    // --arg key1   'data' \
    // --arg value1 "" \
    // --arg key2   'error' \
    // --arg value2 '' \
    // '. | .[$key0]=$value0 | .[$key1]=$value1 | .[$key2]=$value2' \
    // <<<'{}'
    m.Response(myEv, func(p *pluggable.Plugin, r *pluggable.EventResponse) { ... }) 

    // Emit events, they are encoded and passed as JSON payloads to the plugins.
    // In our case, test-foo will receive the map as JSON
    m.Publish(myEv,  map[string]string{"foo": "bar"})
}

Plugin processed data

The interface passed to Publish gets marshalled in JSON in a event struct of the following form:

type Event struct {
	Name EventType `json:"name"`
	Data string    `json:"data"`
	File string    `json:"file"`
}

An example bash plugin could be, for example:

#!/bin/bash

event="$1"
payload="$2"
if [ "$event" == "something.to.hook.on" ]; then
  custom_data=$(echo "$payload" | jq -r .data | jq -r .foo )
  ...
fi

Which can be called by

m.Publish(myEv,  map[string]string{"foo": "bar"})

To note, when the payload exceeds the threshold size the payload published with Publish is written into a temporary file and the file location is sent to the plugin with the Event file field, so for example, a plugin should expect data in a file if the publisher expects to send big chunk of data:

#!/bin/bash
data_file="$(echo $2 | jq -r .file)"
if [ -n "${data_file}" ]; then
    payload="$(cat $data_file)"

...
fi

Writing plugin in golang

It is present a FactoryPlugin which allows to create plugins in golang, consider:

import "github.com/mudler/go-pluggable"

func main() {
    var myEv pluggable.EventType = "event"

    factory := pluggable.NewPluginFactory()
    factory.Add(myEv, func(e *plugable.Event) pluggable.EventResponse { return EventResponse{ ... })

    factory.Run(os.Args[1], os.Stdin, os.Stdout)
}

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

This section is empty.

Functions ΒΆ

This section is empty.

Types ΒΆ

type Event ΒΆ

type Event struct {
	Name EventType `json:"name"`
	Data string    `json:"data"`
	File string    `json:"file"` // If Data >> 10K write content to file instead
}

Event describes the event structure. Contains a Name field and a Data field which is marshalled in JSON

func NewEvent ΒΆ

func NewEvent(name EventType, obj interface{}) (*Event, error)

NewEvent returns a new event which can be used for publishing the obj gets automatically serialized in json.

func (Event) Copy ΒΆ

func (e Event) Copy() *Event

Copy returns a copy of Event

func (Event) JSON ΒΆ

func (e Event) JSON() (string, error)

JSON returns the stringified JSON of the Event

func (Event) ResponseEventName ΒΆ

func (e Event) ResponseEventName(s string) EventType

type EventResponse ΒΆ

type EventResponse struct {
	State string `json:"state"`
	Data  string `json:"data"`
	Error string `json:"error"`
	Logs  string `json:"log"`
}

EventResponse describes the event response structure It represent the JSON response from plugins

func (EventResponse) Errored ΒΆ

func (r EventResponse) Errored() bool

Errored returns true if the response contains an error

func (EventResponse) Unmarshal ΒΆ

func (r EventResponse) Unmarshal(i interface{}) error

Unmarshal decodes the json payload in the given parameteer

type EventType ΒΆ

type EventType string

EventType describes an event type

type FactoryPlugin ΒΆ

type FactoryPlugin struct {
	EventType     EventType
	PluginHandler PluginHandler
}

type Manager ΒΆ

type Manager struct {
	Plugins []Plugin
	Events  []EventType
	Bus     *emission.Emitter
}

Manager describes a set of Plugins and a set of Event types which are subscribed to a message bus

func NewManager ΒΆ

func NewManager(events []EventType) *Manager

NewManager returns a manager instance with a new bus and

func (*Manager) Autoload ΒΆ

func (m *Manager) Autoload(prefix string, extensionpath ...string) *Manager

Autoload automatically loads plugins binaries prefixed by 'prefix' in the current path optionally takes a list of paths to look also into

func (*Manager) Load ΒΆ

func (m *Manager) Load(extname ...string) *Manager

Load finds the binaries given as parameter (without path) and scan the system $PATH to retrieve those automatically

func (*Manager) Publish ΒΆ

func (m *Manager) Publish(event EventType, obj interface{}) (*Manager, error)

Publish is a wrapper around NewEvent and the Manager internal Bus publishing system It accepts optionally a list of functions that are called with the plugin result (only once)

func (*Manager) Register ΒΆ

func (m *Manager) Register() *Manager

Register subscribes the plugin to its internal bus

func (*Manager) Response ΒΆ

func (m *Manager) Response(event EventType, listener ...func(p *Plugin, r *EventResponse)) *Manager

Response binds a set of listeners to an event type. The listeners are called for each result from every plugin when Publish is called.

func (*Manager) Subscribe ΒΆ

func (m *Manager) Subscribe(b *emission.Emitter) *Manager

Subscribe subscribes the plugin to the events in the given bus

type Plugin ΒΆ

type Plugin struct {
	Name       string
	Executable string
}

Plugin describes binaries to be hooked on events, with common js input, and common js output

func (Plugin) Run ΒΆ

func (p Plugin) Run(e Event) (EventResponse, error)

Run runs the Event on the plugin, and returns an EventResponse

type PluginFactory ΒΆ

type PluginFactory map[EventType]PluginHandler

PluginFactory is a collection of handlers for a given event type. a plugin has to respond to multiple events and it always needs to return an Event response as result

func NewPluginFactory ΒΆ

func NewPluginFactory(p ...FactoryPlugin) PluginFactory

func (PluginFactory) Add ΒΆ

func (p PluginFactory) Add(ev EventType, ph PluginHandler)

Add associates an handler to an event type

func (PluginFactory) Run ΒΆ

func (p PluginFactory) Run(name EventType, r io.Reader, w io.Writer) error

Run runs the PluginHandler given a event type and a payload

The result is written to the writer provided as argument.

type PluginHandler ΒΆ

type PluginHandler func(*Event) EventResponse

PluginHandler represent a generic plugin which talks go-pluggable API It receives an event, and is always expected to give a response

Jump to

Keyboard shortcuts

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