update 'middleware' types | rename driver.Driver.Load() into RunController() | add driver.Driver.LoadMiddleware() | add driver management to middleware.Registry at creation | [TODO] implement diver.Generic.LoadMiddleware()
This commit is contained in:
parent
74e4ce83cb
commit
2cfc5a2ba0
|
@ -9,8 +9,8 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// Load implements the Driver interface
|
||||
func (d *Generic) Load(_path []string, _method string) (func(response.Arguments) response.Response, e.Error) {
|
||||
// RunController implements the Driver interface
|
||||
func (d *Generic) RunController(_path []string, _method string) (func(response.Arguments) response.Response, e.Error) {
|
||||
|
||||
/* (1) Build controller path */
|
||||
path := strings.Join(_path, "-")
|
||||
|
|
|
@ -4,12 +4,13 @@ import (
|
|||
"fmt"
|
||||
"git.xdrm.io/go/aicra/err"
|
||||
"git.xdrm.io/go/aicra/response"
|
||||
"net/http"
|
||||
"plugin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Load implements the Driver interface
|
||||
func (d *Plugin) Load(_path []string, _method string) (func(response.Arguments) response.Response, err.Error) {
|
||||
// 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, "-")
|
||||
|
@ -44,3 +45,45 @@ func (d *Plugin) Load(_path []string, _method string) (func(response.Arguments)
|
|||
|
||||
return callable, err.Success
|
||||
}
|
||||
|
||||
// LoadMiddleware returns a new middleware function; it must be a
|
||||
// valid and existing folder/filename file with or without the .so extension
|
||||
// it must be located in the relative directory .build/middleware
|
||||
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("Plugin 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) Export wanted properties */
|
||||
inspect, err := p.Lookup("Inspect")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Missing method 'Inspect()'; %s", err)
|
||||
}
|
||||
|
||||
/* (5) Cast Inspect */
|
||||
mware, ok := inspect.(func(http.Request, *[]string))
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Inspect() is malformed")
|
||||
}
|
||||
|
||||
/* (6) Add type to registry */
|
||||
return mware, nil
|
||||
}
|
||||
|
|
|
@ -3,26 +3,28 @@ package driver
|
|||
import (
|
||||
"git.xdrm.io/go/aicra/err"
|
||||
"git.xdrm.io/go/aicra/response"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Driver defines the driver interface to load controller/middleware implementation or executables
|
||||
type Driver interface {
|
||||
Load(_path []string, _method string) (func(response.Arguments) response.Response, err.Error)
|
||||
RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error)
|
||||
LoadMiddleware(_path string) (func(http.Request, *[]string), error)
|
||||
}
|
||||
|
||||
// Generic tells the aicra instance to use the generic driver to load controller's executables
|
||||
// Generic tells the aicra instance to use the generic driver to load controller/middleware executables
|
||||
//
|
||||
// It will call an executable with the json input into the standard input (argument 1)
|
||||
// the HTTP method is send as the key _HTTP_METHOD_ (in upper case)
|
||||
// The standard output must be a json corresponding to the data
|
||||
//
|
||||
// FILE STRUCTURE
|
||||
// CONTROLLER FILE STRUCTURE
|
||||
// --------------
|
||||
// - the root (/) controller executable must be named <WORKDIR>/controller/ROOT
|
||||
// - the a/b/c controller executable must be named <WORKDIR>/controller/a/b/c
|
||||
type Generic struct{}
|
||||
|
||||
// Plugin tells the aicra instance to use the plugin driver to load controller's executables
|
||||
// Plugin tells the aicra instance to use the plugin driver to load controller/middleware executables
|
||||
//
|
||||
// It will load go .so plugins with the following interface :
|
||||
//
|
||||
|
@ -33,7 +35,7 @@ type Generic struct{}
|
|||
// Delete(d i.Arguments, r *i.Response) i.Response
|
||||
// }
|
||||
//
|
||||
// FILE STRUCTURE
|
||||
// CONTROLLER FILE STRUCTURE
|
||||
// --------------
|
||||
// - the root (/) controller executable must be named <WORKDIR>/controller/ROOT/main.so
|
||||
// - the a/b/c controller executable must be named <WORKDIR>/controller/a/b/c/main.so
|
||||
|
@ -43,13 +45,13 @@ type Generic struct{}
|
|||
// The compilation is handled with the command-line tool `aicra <WORKDIR>`
|
||||
type Plugin struct{}
|
||||
|
||||
// FastCGI tells the aicra instance to use the fastcgi driver to load controller's executables
|
||||
// FastCGI tells the aicra instance to use the fastcgi driver to load controller/middleware executables
|
||||
//
|
||||
// Warning: PHP only
|
||||
//
|
||||
// It will use the fastcgi protocol with php at <host>:<port>
|
||||
//
|
||||
// FILE STRUCTURE
|
||||
// CONTROLLER FILE STRUCTURE
|
||||
// --------------
|
||||
// - the root (/) controller executable must be named <WORKDIR>/controller/ROOT.php
|
||||
// - the a/b/c controller executable must be named <WORKDIR>/controller/a/b/c.php
|
||||
|
|
|
@ -96,6 +96,6 @@ func FetchFormData(req *http.Request) map[string]interface{} {
|
|||
// checks for its given method ('Get', 'Post', 'Put', or 'Delete')
|
||||
func (i *Request) LoadController(_method string, _driver driver.Driver) (func(response.Arguments) response.Response, err.Error) {
|
||||
|
||||
return _driver.Load(i.Path, _method)
|
||||
return _driver.RunController(i.Path, _method)
|
||||
|
||||
}
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.xdrm.io/go/aicra/driver"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"plugin"
|
||||
"strings"
|
||||
"path"
|
||||
)
|
||||
|
||||
// CreateRegistry creates an empty middleware registry
|
||||
// - if loadDir is set -> load all available middlewares
|
||||
// inside the local ./middleware folder
|
||||
func CreateRegistry(loadDir ...string) *Registry {
|
||||
func CreateRegistry(_driver driver.Driver, loadDir ...string) *Registry {
|
||||
|
||||
/* (1) Create registry */
|
||||
reg := &Registry{
|
||||
Middlewares: make([]MiddleWare, 0),
|
||||
Middlewares: make([]*Wrapper, 0),
|
||||
}
|
||||
|
||||
/* (2) If no default to use -> empty registry */
|
||||
|
@ -24,81 +23,31 @@ func CreateRegistry(loadDir ...string) *Registry {
|
|||
return reg
|
||||
}
|
||||
|
||||
/* (3) List types */
|
||||
plugins, err := ioutil.ReadDir(loadDir[0])
|
||||
/* (3) List middleware files */
|
||||
files, err := ioutil.ReadDir(loadDir[0])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
/* (4) Else try to load each given default */
|
||||
for _, file := range plugins {
|
||||
for _, file := range files {
|
||||
|
||||
// ignore non .so files
|
||||
if !strings.HasSuffix(file.Name(), ".so") {
|
||||
continue
|
||||
}
|
||||
|
||||
err := reg.add(file.Name())
|
||||
mwFunc, err := _driver.LoadMiddleware(path.Join(loadDir[0], file.Name()))
|
||||
if err != nil {
|
||||
log.Fatalf("Cannot load plugin '%s'", file.Name())
|
||||
log.Printf("Cannot load middleware '%s' | %s", file.Name(), err)
|
||||
}
|
||||
reg.Middlewares = append(reg.Middlewares, &Wrapper{Inspect: mwFunc})
|
||||
|
||||
}
|
||||
|
||||
return reg
|
||||
}
|
||||
|
||||
// add adds a middleware to the registry; it must be a
|
||||
// valid and existing plugin name with or without the .so extension
|
||||
// it must be located in the relative directory .build/middleware
|
||||
func (reg *Registry) add(pluginName string) error {
|
||||
|
||||
/* (1) Check plugin name */
|
||||
if len(pluginName) < 1 {
|
||||
return fmt.Errorf("Plugin name must not be empty")
|
||||
}
|
||||
|
||||
/* (2) Check if valid plugin name */
|
||||
if strings.ContainsAny(pluginName, "/") {
|
||||
return fmt.Errorf("'%s' can only be a name, not a path", pluginName)
|
||||
}
|
||||
|
||||
/* (3) Check plugin extension */
|
||||
if !strings.HasSuffix(pluginName, ".so") {
|
||||
pluginName = fmt.Sprintf("%s.so", pluginName)
|
||||
}
|
||||
|
||||
/* (4) Try to load the plugin */
|
||||
p, err := plugin.Open(fmt.Sprintf(".build/middleware/%s", pluginName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
/* (5) Export wanted properties */
|
||||
inspect, err := p.Lookup("Inspect")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Missing method 'Inspect()'; %s", err)
|
||||
}
|
||||
|
||||
/* (6) Cast Inspect */
|
||||
inspectCast, ok := inspect.(func(http.Request, *Scope))
|
||||
if !ok {
|
||||
return fmt.Errorf("Inspect() is malformed")
|
||||
}
|
||||
|
||||
/* (7) Add type to registry */
|
||||
reg.Middlewares = append(reg.Middlewares, MiddleWare{
|
||||
Inspect: inspectCast,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run executes all middlewares (default browse order)
|
||||
func (reg Registry) Run(req http.Request) Scope {
|
||||
func (reg Registry) Run(req http.Request) []string {
|
||||
|
||||
/* (1) Initialise scope */
|
||||
scope := Scope{}
|
||||
scope := make([]string, 0)
|
||||
|
||||
/* (2) Execute each middleware */
|
||||
for _, m := range reg.Middlewares {
|
||||
|
|
|
@ -7,20 +7,26 @@ import (
|
|||
// Scope represents a list of scope processed by middlewares
|
||||
// and used by the router to block/allow some uris
|
||||
// it is also passed to controllers
|
||||
//
|
||||
// DISCLAIMER: it is used to help developers but for compatibility
|
||||
// purposes, the type is always used as its definition ([]string)
|
||||
type Scope []string
|
||||
|
||||
// Inspector updates the @Scope passed to it according to
|
||||
// the @http.Request
|
||||
type Inspector func(http.Request, *Scope)
|
||||
type MiddlewareFunc func(http.Request, *[]string)
|
||||
|
||||
// MiddleWare contains all necessary methods
|
||||
// for a Middleware provided by user/developer
|
||||
type MiddleWare struct {
|
||||
Inspect func(http.Request, *Scope)
|
||||
// Middleware updates the @Scope passed to it according to
|
||||
// the @http.Request
|
||||
type Middleware interface {
|
||||
Inspect(http.Request, *[]string)
|
||||
}
|
||||
|
||||
// Wrapper is a struct that stores middleware Inspect() method
|
||||
type Wrapper struct {
|
||||
Inspect func(http.Request, *[]string)
|
||||
}
|
||||
|
||||
// Registry represents a registry containing all registered
|
||||
// middlewares to be processed before routing any request
|
||||
type Registry struct {
|
||||
Middlewares []MiddleWare
|
||||
Middlewares []*Wrapper
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func New(_path string, _driver driver.Driver) (*Server, error) {
|
|||
i.checker = checker.CreateRegistry(".build/type")
|
||||
|
||||
/* (4) Default middleware registry */
|
||||
i.middleware = middleware.CreateRegistry(".build/middleware")
|
||||
i.middleware = middleware.CreateRegistry(_driver, ".build/middleware")
|
||||
|
||||
return i, nil
|
||||
|
||||
|
|
Loading…
Reference in New Issue