goplugin

package module
v1.0.0-alpha.0 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2020 License: Apache-2.0 Imports: 10 Imported by: 0

README

quadroops/goplugin

This package is a library to implement modular and pluggable architecture for application using Golang's language.

This library inspired from hashicorp's plugin architecture, but just to implement it in different ways, such as:

  1. Using single file configuration to explore all available plugins (customizable)
  2. Adding REST as an alternatives of communication protocols

We have a same direction with hashicorp's plugin:

  1. Using subprocess
  2. Supported multiple languages (as long as support with GRPC/REST)

Why we doesn't support golang's native plugin ? It's because using Symbol for exported variable and methods, it's easy for simple plugin but it will harder to maintain for complex application


Flows

// need a way to discover available plugins
[host] -----<discover>---> [plugin]


// start subprocess, should be sharing a same PID
[host] ------<exec>-----> [plugin]


// communicate via REST or GRPC 
[host] ---<communicate>------> [plugin]

We have three main flows:

  • Discover
  • Exec
  • Communication via rpc

Current supported communication protocols:


Usages

Basic usages:

package main

import (
    "log"

    "github.com/quadroops/goplugin"
)

func main() {
    hostA := goplugin.New("hostA")
    hostB := goplugin.New("hostB")
    
    // stop all available plugins, when main system is shutting down
    defer func() {
        hostA.GetPluginInstance().KillAll()
        hostB.GetPluginInstance().KillAll()
    }()

    pluggable, err := goplugin.Register(
        hostA,
        hostB,
    )
    if err != nil {
        panic(err)
    }

    err = pluggable.Setup()
    if err != nil {
        panic(err)
    }

    aPlugins, err := pluggable.FromHost("hostA")
    if err != nil {
        panic(err)
    }

    bPlugins, err := pluggable.FromHost("hostB")
    if err != nil {
        panic(err)
    }

    err = aPlugins.Run("plugin1", 8081)
    if err != nil {
        panic(err)
    }

    err = bPlugins.Run("plugin2", 8082)
    if err != nil {
        panic(err)
    }

    // get plugin's instance, you dont need to decide which protocol will be used 
    // just use our helper, or even you can create your own helper as long as, your helper
    // function follow caller.Build type
    //
    // after get your plugin's instance, now you can communicate with your plugin via REST/GRPC
    plugin1, err := aPlugins.Get(
        "plugin1", 
        8081, 
        goplugin.BuildProtocol(&goplugin.ProtocolOption{
            RestAddr: "http://localhost",
            RestTimeout: 10, // this configuration is optional
        })
    )

    if err != nil {
        panic(err)
    }

    // call plugin's ping method
    respPing, err := plugin1.Ping()
    if err != nil {
        panic(err)
    }

    log.Printf("Resp: %s", respPing)

    // call plugin's exec method
    respExec, err := plugin1.Exec("test.command", []byte("hello"))
    if err != nil {
        panic(err)
    }

    log.Printf("Resp: %s", respExec)

    // you can use a same ways for bPlugins
}

Assume you need to customize config Checker and Parser, imagine you want to using a database like Mongodb as configuration source.

// implement discover.Checker
func Check() string {
    return 'mongodb://localhost:27017/dbname'
}

// implement discover.SourceReader
func MongoSourceReader(source string) ([]byte, error) {
    // parse configurations from mongodb
}

// implement discover.Parser
func MongoParse(content []byte) (*discover.PluginConfig, error) {
    // map configurations to discover.PluginConfig
}

hostA := goplugin.New("hostA", 
    goplugin.WithCustomConfigChecker(Check), 
    goplugin.WithCustomConfigParser(MongoSourceReader, MongoParse),
)

// stop all available plugins, when main system is shutting down
defer func() {
    hostA.GetPluginInstance().KillAll()
}()

pluggable := goplugin.Register(
    hostA,
)

err = pluggable.Setup()
if err != nil {
    panic(err)
}

Customizated components available for:

  • ConfigChecker (default: get toml file path)
  • ConfigParser (default: toml parser)
  • ProcessInstance (default: subprocess)
  • HostIdentityChecker (default: MD5Checker)

Available options for customization:

  • goplugin.WithCustomConfigChecker
  • goplugin.WithCustomConfigParser
  • goplugin.WithCustomIdentityChecker
  • goplugin.WithCustomProcess

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildProtocol

func BuildProtocol(opt *ProtocolOption) caller.Builder

BuildProtocol a helper to check and also generate a default protocol should be used like a REST or GRPC

Types

type GoPlugin

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

GoPlugin .

func New

func New(hostName string, opts ...Option) *GoPlugin

New used to create new instance of GoPlugin, you can provide customization here by giving goplugin.Option

func (*GoPlugin) Build

func (g *GoPlugin) Build() (*host.Builder, error)

Build used to compile current host instance into consumed state of host.Builder

func (*GoPlugin) GetProcessInstance

func (g *GoPlugin) GetProcessInstance() *process.Instance

GetProcessInstance .

type Option

type Option func(*GoPlugin)

Option used to customize default objects

func WithCustomConfigChecker

func WithCustomConfigChecker(adapters ...discover.Checker) Option

WithCustomConfigChecker used to customize config checker, the parameter must be implement discover.Checker

func WithCustomConfigParser

func WithCustomConfigParser(parserAdapter discover.Parser, sourceAdapter discover.SourceReader) Option

WithCustomConfigParser used to customize config reader & parser, given adapters must be implement discover.Parser and discover.SourceReader interfaces

func WithCustomIdentityChecker

func WithCustomIdentityChecker(adapter host.IdentityChecker) Option

WithCustomIdentityChecker used to customize plugin's identity checker, given adapter must implement host.IdentityChecker

func WithCustomProcess

func WithCustomProcess(runner process.Runner, processes process.ProcessesBuilder) Option

WithCustomProcess used to customize process runner and process data builder (including registry)

type ProtocolOption

type ProtocolOption struct {
	RestAddr    string
	RestTimeout int
	GrpcClient  driver.MakeClient
}

ProtocolOption used to configure rest or grpc options You have to choose between rest or grpc, if your plugin using rest, than ignore grpc option, and vice versa, but you can't ignore them both

type Registry

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

Registry used as wrapper of executor object

func Register

func Register(hostPlugins ...*GoPlugin) (*Registry, error)

Register used to collect available hosts and run executor behind it

func (*Registry) FromHost

func (r *Registry) FromHost(hostname string) (*executor.Container, error)

FromHost here is just a proxy to call FromHot from executor

func (*Registry) Setup

func (r *Registry) Setup() error

Setup .

Jump to

Keyboard shortcuts

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