added basic plugin structure

This commit is contained in:
2022-11-01 14:26:54 +01:00
commit a693cbad37
18 changed files with 481 additions and 0 deletions

View File

@@ -0,0 +1 @@
package script

5
pkg/register/plugin.go Normal file
View File

@@ -0,0 +1,5 @@
package register
type Plugin interface {
About() string
}

View File

@@ -0,0 +1,19 @@
package register
import (
"net/rpc"
"github.com/hashicorp/go-plugin"
)
type PluginAPI struct {
Impl Plugin
}
func (pa *PluginAPI) Server(*plugin.MuxBroker) (any, error) {
return &PluginServer{Impl: pa.Impl}, nil
}
func (*PluginAPI) Client(b *plugin.MuxBroker, c *rpc.Client) (any, error) {
return &PluginClient{client: c}, nil
}

View File

@@ -0,0 +1,48 @@
package register
import (
"context"
"os"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-plugin"
)
type PluginBuilder struct {
serveConfig *plugin.ServeConfig
}
func NewPluginBuilder(name string, p Plugin) *PluginBuilder {
logger := hclog.New(&hclog.LoggerOptions{
Level: hclog.Trace,
Output: os.Stderr,
JSONFormat: false,
})
var pluginMap = map[string]plugin.Plugin{
name: &PluginAPI{
Impl: p,
},
}
serveConfig := &plugin.ServeConfig{
HandshakeConfig: plugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "char",
},
Plugins: pluginMap,
Logger: logger,
}
return &PluginBuilder{
serveConfig: serveConfig,
}
}
func (pr *PluginBuilder) Serve(ctx context.Context) error {
plugin.Serve(
pr.serveConfig,
)
return nil
}

View File

@@ -0,0 +1,22 @@
package register
import (
"log"
"net/rpc"
)
type PluginClient struct {
client *rpc.Client
}
var _ Plugin = &PluginClient{}
func (pc *PluginClient) About() string {
var resp string
err := pc.client.Call("Plugin.About", new(any), &resp)
if err != nil {
log.Fatal(err)
}
return resp
}

View File

@@ -0,0 +1,147 @@
package register
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-plugin"
"golang.org/x/sync/errgroup"
)
type PluginRegisterBuilder struct {
plugins map[string]PluginAPI
}
func NewPluginRegisterBuilder() *PluginRegisterBuilder {
return &PluginRegisterBuilder{}
}
func (pr *PluginRegisterBuilder) Add(name, path string) *PluginRegisterBuilder {
pr.plugins[name] = PluginAPI{}
return pr
}
func (pr *PluginRegisterBuilder) Build(ctx context.Context) (*PluginRegister, error) {
clients := make(map[string]*pluginClientWrapper, 0)
errgroup, _ := errgroup.WithContext(ctx)
for name, p := range pr.plugins {
name, p := name, p
errgroup.Go(func() error {
client := plugin.NewClient(&plugin.ClientConfig{
HandshakeConfig: plugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "char",
},
Logger: hclog.New(&hclog.LoggerOptions{
Name: "char",
Output: os.Stdout,
Level: hclog.Debug,
}),
Cmd: exec.Command("sh", "-c", fmt.Sprintf(
"(cd ./.char/plugins/%s; go run plugins/%s/main.go)",
name,
name,
)),
Plugins: map[string]plugin.Plugin{
name: &p,
},
})
rpcClient, err := client.Client()
if err != nil {
return err
}
raw, err := rpcClient.Dispense(name)
if err != nil {
return err
}
pluginApi, ok := raw.(Plugin)
if !ok {
return errors.New("could not cast as plugin")
}
clients[name] = &pluginClientWrapper{
plugin: pluginApi,
client: client,
}
return nil
})
}
err := errgroup.Wait()
if err != nil {
return nil, err
}
return &PluginRegister{
clients: clients,
}, nil
}
// ---
type pluginClientWrapper struct {
plugin Plugin
client *plugin.Client
}
func (pcw *pluginClientWrapper) Close() {
pcw.client.Kill()
}
// ---
type PluginRegister struct {
clients map[string]*pluginClientWrapper
}
func (pr *PluginRegister) Close() error {
errgroup, _ := errgroup.WithContext(context.Background())
for _, c := range pr.clients {
c := c
errgroup.Go(func() error {
c.Close()
return nil
})
}
if err := errgroup.Wait(); err != nil {
return err
}
return nil
}
func (pr *PluginRegister) About(ctx context.Context) (map[string]string, error) {
list := make(map[string]string, len(pr.clients))
errgroup, ctx := errgroup.WithContext(ctx)
for n, c := range pr.clients {
n, c := n, c
errgroup.Go(func() error {
about := c.plugin.About()
list[n] = about
return nil
})
}
if err := errgroup.Wait(); err != nil {
return nil, err
}
return list, nil
}

View File

@@ -0,0 +1,10 @@
package register
type PluginServer struct {
Impl Plugin
}
func (ps *PluginServer) About(args any, resp *string) error {
*resp = ps.Impl.About()
return nil
}