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:
Adrien Marquès 2018-09-28 10:54:13 +02:00
parent 74e4ce83cb
commit 2cfc5a2ba0
7 changed files with 84 additions and 84 deletions

View File

@ -9,8 +9,8 @@ import (
"strings" "strings"
) )
// Load implements the Driver interface // RunController implements the Driver interface
func (d *Generic) Load(_path []string, _method string) (func(response.Arguments) response.Response, e.Error) { func (d *Generic) RunController(_path []string, _method string) (func(response.Arguments) response.Response, e.Error) {
/* (1) Build controller path */ /* (1) Build controller path */
path := strings.Join(_path, "-") path := strings.Join(_path, "-")

View File

@ -4,12 +4,13 @@ import (
"fmt" "fmt"
"git.xdrm.io/go/aicra/err" "git.xdrm.io/go/aicra/err"
"git.xdrm.io/go/aicra/response" "git.xdrm.io/go/aicra/response"
"net/http"
"plugin" "plugin"
"strings" "strings"
) )
// Load implements the Driver interface // RunController implements the Driver interface
func (d *Plugin) Load(_path []string, _method string) (func(response.Arguments) response.Response, err.Error) { func (d *Plugin) RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error) {
/* (1) Build controller path */ /* (1) Build controller path */
path := strings.Join(_path, "-") path := strings.Join(_path, "-")
@ -44,3 +45,45 @@ func (d *Plugin) Load(_path []string, _method string) (func(response.Arguments)
return callable, err.Success 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
}

View File

@ -3,26 +3,28 @@ package driver
import ( import (
"git.xdrm.io/go/aicra/err" "git.xdrm.io/go/aicra/err"
"git.xdrm.io/go/aicra/response" "git.xdrm.io/go/aicra/response"
"net/http"
) )
// Driver defines the driver interface to load controller/middleware implementation or executables // Driver defines the driver interface to load controller/middleware implementation or executables
type Driver interface { 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) // 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 HTTP method is send as the key _HTTP_METHOD_ (in upper case)
// The standard output must be a json corresponding to the data // 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 root (/) controller executable must be named <WORKDIR>/controller/ROOT
// - the a/b/c controller executable must be named <WORKDIR>/controller/a/b/c // - the a/b/c controller executable must be named <WORKDIR>/controller/a/b/c
type Generic struct{} 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 : // 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 // 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 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 // - 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>` // The compilation is handled with the command-line tool `aicra <WORKDIR>`
type Plugin struct{} 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 // Warning: PHP only
// //
// It will use the fastcgi protocol with php at <host>:<port> // 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 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 // - the a/b/c controller executable must be named <WORKDIR>/controller/a/b/c.php

View File

@ -96,6 +96,6 @@ func FetchFormData(req *http.Request) map[string]interface{} {
// checks for its given method ('Get', 'Post', 'Put', or 'Delete') // 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) { 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)
} }

View File

@ -1,22 +1,21 @@
package middleware package middleware
import ( import (
"fmt" "git.xdrm.io/go/aicra/driver"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
"plugin" "path"
"strings"
) )
// CreateRegistry creates an empty middleware registry // CreateRegistry creates an empty middleware registry
// - if loadDir is set -> load all available middlewares // - if loadDir is set -> load all available middlewares
// inside the local ./middleware folder // inside the local ./middleware folder
func CreateRegistry(loadDir ...string) *Registry { func CreateRegistry(_driver driver.Driver, loadDir ...string) *Registry {
/* (1) Create registry */ /* (1) Create registry */
reg := &Registry{ reg := &Registry{
Middlewares: make([]MiddleWare, 0), Middlewares: make([]*Wrapper, 0),
} }
/* (2) If no default to use -> empty registry */ /* (2) If no default to use -> empty registry */
@ -24,81 +23,31 @@ func CreateRegistry(loadDir ...string) *Registry {
return reg return reg
} }
/* (3) List types */ /* (3) List middleware files */
plugins, err := ioutil.ReadDir(loadDir[0]) files, err := ioutil.ReadDir(loadDir[0])
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
/* (4) Else try to load each given default */ /* (4) Else try to load each given default */
for _, file := range plugins { for _, file := range files {
// ignore non .so files mwFunc, err := _driver.LoadMiddleware(path.Join(loadDir[0], file.Name()))
if !strings.HasSuffix(file.Name(), ".so") {
continue
}
err := reg.add(file.Name())
if err != nil { 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 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) // 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 */ /* (1) Initialise scope */
scope := Scope{} scope := make([]string, 0)
/* (2) Execute each middleware */ /* (2) Execute each middleware */
for _, m := range reg.Middlewares { for _, m := range reg.Middlewares {

View File

@ -7,20 +7,26 @@ import (
// Scope represents a list of scope processed by middlewares // Scope represents a list of scope processed by middlewares
// and used by the router to block/allow some uris // and used by the router to block/allow some uris
// it is also passed to controllers // 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 type Scope []string
// Inspector updates the @Scope passed to it according to type MiddlewareFunc func(http.Request, *[]string)
// the @http.Request
type Inspector func(http.Request, *Scope)
// MiddleWare contains all necessary methods // Middleware updates the @Scope passed to it according to
// for a Middleware provided by user/developer // the @http.Request
type MiddleWare struct { type Middleware interface {
Inspect func(http.Request, *Scope) 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 // Registry represents a registry containing all registered
// middlewares to be processed before routing any request // middlewares to be processed before routing any request
type Registry struct { type Registry struct {
Middlewares []MiddleWare Middlewares []*Wrapper
} }

View File

@ -50,7 +50,7 @@ func New(_path string, _driver driver.Driver) (*Server, error) {
i.checker = checker.CreateRegistry(".build/type") i.checker = checker.CreateRegistry(".build/type")
/* (4) Default middleware registry */ /* (4) Default middleware registry */
i.middleware = middleware.CreateRegistry(".build/middleware") i.middleware = middleware.CreateRegistry(_driver, ".build/middleware")
return i, nil return i, nil