Было много головной боли с плагинами Go, особенно версия компилятора плагина должна точно соответствовать версии компилятора программы. Но пример работает.
runner / runner.go
package main
import (
"context"
"fmt"
"os"
"plugin"
"reflect"
"../gateway"
"../dep"
)
var a *gateway.Gateway
func main() {
myModule := os.Args[1]
if _, err := plugin.Open(myModule); err != nil {
os.Exit(1)
}
mod, err := dep.NewModule()
if err != nil {
os.Exit(1)
}
a = gateway.NewGW()
ctx := context.WithValue(context.Background(), "gateway", a)
modreflect, err := mod.Init(ctx, dep.Config{})
if err != nil {
os.Exit(1)
}
if !modreflect.IsValid() {
os.Exit(1)
}
modnode, err := mod.Start(ctx)
if err != nil {
os.Exit(1002)
}
for {
if len(modnode) <= 0 {
break
}
modnoderefl := modreflect.MethodByName(modnode)
if !modnoderefl.IsValid() {
break
}
result := modnoderefl.Call([]reflect.Value{reflect.ValueOf(ctx)})
if len(result) != 2 {
break
}
modnode = result[0].String()
}
mod.End(ctx)
}
gateway / gateway.go
package gateway
type Gateway struct {}
fun NewGW() *Gateway {
a := Gateway{}
return &a
}
dep / dep.go
package dep
import (
"errors"
"context"
"reflect"
)
// Config is a configuration provider.
type Config map[string]interface{}
// Module is the interface implementated by types that
// register themselves as modular plug-ins.
type Module interface {
Init(ctx context.Context, config Config) (reflect.Value,error)
Start(ctx context.Context) (string,error)
End(ctx context.Context) error
}
var themod = []func() Module{}
func RegisterModule(ctor func() Module) {
themod = append(themod, ctor)
}
func NewModule() (Module, error) {
if len(themod) == 0 {
return nil, errors.New("Module not registered")
}
return themod[0](), nil
}
framework / framework.go
package framework
import (
"fmt"
"context"
"../gateway"
)
type PlayFileInput struct {
Path string
}
func Play(ctx context.Context, p PlayFileInput) error {
if a := ctx.Value("gateway"); a != nil {
if a.(*gateway.Gateway) != nil {
_, err := a.(*gateway.Gateway).Exec("Playback", p.Path)
return err
}
}
return nil
}
modules / sample.go
package main
import "C"
import (
"context"
"fmt"
"os"
"reflect"
"../dep"
"../framework"
)
type MyModuleImpl struct {}
func init() {
dep.RegisterModule(func() dep.Module {
return &MyModuleImpl{}
})
}
func (m *MyModuleImpl) Init(ctx context.Context, config dep.Config) (reflect.Value, error) {
return reflect.ValueOf(m), nil
}
func (m *MyModuleImpl) Start(ctx context.Context) (string,error) {
return "Menu_1",nil
}
func (n *MyModuleImpl)Menu_1(ctx context.Context) (string, error) {
framework.Play(ctx, framework.PlayFileInput{Path: "welcome.wav"})
return "Menu_2",nil
}
func (n *MyModuleImpl)Menu_2(ctx context.Context) (string, error) {
return "Menu_3", nil
}
// ....
// ....
func (m *MyModuleImpl) End(ctx context.Context) error {
return nil
}