aicra/driver/plugin.go

124 lines
2.9 KiB
Go

package driver
import (
"fmt"
"git.xdrm.io/go/aicra/err"
"git.xdrm.io/go/aicra/response"
"net/http"
"path/filepath"
"plugin"
"strings"
)
// Name returns the driver name
func (d Plugin) Name() string { return "plugin" }
// Path returns the universal path from the source path
func (d Plugin) Path(_root, _folder, _src string) string {
return filepath.Dir(_src)
}
// Source returns the source path from the universal path
func (d Plugin) Source(_root, _folder, _path string) string {
return filepath.Join(_root, _folder, _path, "main.go")
}
// Build returns the build path from the universal path
func (d Plugin) Build(_root, _folder, _path string) string {
return fmt.Sprintf("%s.so", filepath.Join(_root, ".build", _folder, _path))
}
// Compiled returns whether the driver has to be build
func (d Plugin) Compiled() bool { return true }
// RunController implements the Driver interface
func (d *Plugin) RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error) {
/* (1) Build controller path */
path := strings.Join(_path, "-")
if len(path) == 0 {
path = fmt.Sprintf(".build/controller/ROOT.so")
} else {
path = fmt.Sprintf(".build/controller/%s.so", path)
}
/* (2) Format url */
method := strings.ToLower(_method)
/* (2) Try to load plugin */
p, err2 := plugin.Open(path)
if err2 != nil {
return nil, err.UncallableController
}
/* (3) Try to extract exported field */
m, err2 := p.Lookup("Export")
if err2 != nil {
return nil, err.UncallableController
}
exported, ok := m.(func() Controller)
if !ok {
return nil, err.UncallableController
}
/* (4) Controller */
ctl := exported()
/* (4) Check signature */
switch method {
case "get":
return ctl.Get, err.Success
case "post":
return ctl.Post, err.Success
case "put":
return ctl.Put, err.Success
case "delete":
return ctl.Delete, err.Success
}
fmt.Printf("method: %s\n", method)
return nil, err.UncallableMethod
}
// LoadMiddleware returns a new middleware function; it must be a
// valid and existing folder/filename file with the .so extension
func (d *Plugin) LoadMiddleware(_path string) (func(http.Request, *[]string), error) {
// ignore non .so files
if !strings.HasSuffix(_path, ".so") {
return nil, fmt.Errorf("Invalid name")
}
/* (1) Check plugin name */
if len(_path) < 1 {
return nil, fmt.Errorf("Middleware name must not be empty")
}
/* (2) Check plugin extension */
if !strings.HasSuffix(_path, ".so") {
_path = fmt.Sprintf("%s.so", _path)
}
/* (3) Try to load the plugin */
p, err := plugin.Open(_path)
if err != nil {
return nil, err
}
/* (4) Extract exported fields */
mw, err := p.Lookup("Export")
if err != nil {
return nil, fmt.Errorf("Missing method 'Inspect()'; %s", err)
}
exported, ok := mw.(func() Middleware)
if !ok {
return nil, fmt.Errorf("Inspect() is malformed")
}
/* (5) Return Inspect method */
return exported().Inspect, nil
}