implement driver for type checkers | move controller/middleware/checker definition inside the 'driver' package (all uses are exported from this place) | now driver.Driver returns 'Controller', 'Middleware', and 'Checker' in the interface | a lot a junk
This commit is contained in:
parent
37fe30ebc7
commit
d406338777
|
@ -1,14 +1,7 @@
|
||||||
package driver
|
package driver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
e "git.xdrm.io/go/aicra/err"
|
|
||||||
"git.xdrm.io/go/aicra/response"
|
|
||||||
"net/http"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generic tells the aicra instance to use the generic driver to load controller/middleware executables
|
// Generic tells the aicra instance to use the generic driver to load controller/middleware executables
|
||||||
|
@ -40,125 +33,19 @@ func (d Generic) Build(_root, _folder, _path string) string {
|
||||||
// Compiled returns whether the driver has to be build
|
// Compiled returns whether the driver has to be build
|
||||||
func (d Generic) Compiled() bool { return false }
|
func (d Generic) Compiled() bool { return false }
|
||||||
|
|
||||||
// RunController implements the Driver interface
|
// LoadController implements the Driver interface
|
||||||
func (d *Generic) RunController(_path []string, _method string) (func(response.Arguments) response.Response, e.Error) {
|
func (d *Generic) LoadController(_path string) (Controller, error) {
|
||||||
|
return GenericController(_path), nil
|
||||||
/* (1) Build controller path */
|
|
||||||
path := strings.Join(_path, "-")
|
|
||||||
if len(path) == 0 {
|
|
||||||
path = fmt.Sprintf("./controller/ROOT")
|
|
||||||
} else {
|
|
||||||
path = fmt.Sprintf("./controller/%s", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (2) Format method */
|
|
||||||
method := strings.ToUpper(_method)
|
|
||||||
|
|
||||||
return func(d response.Arguments) response.Response {
|
|
||||||
|
|
||||||
res := response.New()
|
|
||||||
|
|
||||||
/* (1) Prepare stdin data */
|
|
||||||
d["_HTTP_METHOD_"] = method
|
|
||||||
stdin, err := json.Marshal(d)
|
|
||||||
if err != nil {
|
|
||||||
res.Err = e.UncallableController
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (2) Try to load command with <stdin> -> stdout */
|
|
||||||
cmd := exec.Command(path, string(stdin))
|
|
||||||
|
|
||||||
stdout, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
res.Err = e.UncallableController
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Get output json */
|
|
||||||
var outputI interface{}
|
|
||||||
err = json.Unmarshal(stdout, &outputI)
|
|
||||||
if err != nil {
|
|
||||||
res.Err = e.UncallableController
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
|
|
||||||
output, ok := outputI.(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
res.Err = e.UncallableController
|
|
||||||
return *res
|
|
||||||
}
|
|
||||||
|
|
||||||
res.Err = e.Success
|
|
||||||
|
|
||||||
// extract error (success by default or on error)
|
|
||||||
if outErr, ok := output["error"]; ok {
|
|
||||||
errCode, ok := outErr.(float64)
|
|
||||||
if ok {
|
|
||||||
res.Err = e.Error{Code: int(errCode), Reason: "unknown reason", Arguments: nil}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(output, "error")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (4) fill response */
|
|
||||||
for k, v := range output {
|
|
||||||
res.Set(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return *res
|
|
||||||
|
|
||||||
}, e.Success
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadMiddleware returns a new middleware function; it must be a
|
// LoadMiddleware returns a new middleware; it must be a
|
||||||
// valid and existing folder/filename file
|
// valid and existing folder/filename file
|
||||||
func (d *Generic) LoadMiddleware(_path string) (func(http.Request, *[]string), error) {
|
func (d *Generic) LoadMiddleware(_path string) (Middleware, error) {
|
||||||
|
return GenericMiddleware(_path), nil
|
||||||
/* (1) Check plugin name */
|
}
|
||||||
if len(_path) < 1 {
|
|
||||||
return nil, fmt.Errorf("Middleware name must not be empty")
|
// LoadChecker returns a new middleware; it must be a
|
||||||
}
|
// valid and existing folder/filename file
|
||||||
|
func (d *Generic) LoadChecker(_path string) (Checker, error) {
|
||||||
/* (2) Create method + error */
|
return GenericChecker(_path), nil
|
||||||
return func(_req http.Request, _scope *[]string) {
|
|
||||||
|
|
||||||
/* (1) Prepare stdin data */
|
|
||||||
stdin, err := json.Marshal(_scope)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (2) Try to load command with <stdin> -> stdout */
|
|
||||||
cmd := exec.Command(_path, string(stdin))
|
|
||||||
|
|
||||||
stdout, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Get output json */
|
|
||||||
var outputI interface{}
|
|
||||||
err = json.Unmarshal(stdout, &outputI)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (4) Get as []string */
|
|
||||||
scope, ok := outputI.([]interface{})
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (5) Try to add each value to the scope */
|
|
||||||
for _, v := range scope {
|
|
||||||
stringScope, ok := v.(string)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
*_scope = append(*_scope, stringScope)
|
|
||||||
}
|
|
||||||
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
package driver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
e "git.xdrm.io/go/aicra/err"
|
||||||
|
"git.xdrm.io/go/aicra/response"
|
||||||
|
"net/http"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenericController is the mockup for returning a controller with as a string the path
|
||||||
|
type GenericController string
|
||||||
|
|
||||||
|
func (path GenericController) Get(d response.Arguments) response.Response {
|
||||||
|
|
||||||
|
res := response.New()
|
||||||
|
|
||||||
|
/* (1) Prepare stdin data */
|
||||||
|
stdin, err := json.Marshal(d)
|
||||||
|
if err != nil {
|
||||||
|
res.Err = e.UncallableController
|
||||||
|
return *res
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Try to load command with <stdin> -> stdout */
|
||||||
|
cmd := exec.Command(string(path), string(stdin))
|
||||||
|
|
||||||
|
stdout, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
res.Err = e.UncallableController
|
||||||
|
return *res
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Get output json */
|
||||||
|
var outputI interface{}
|
||||||
|
err = json.Unmarshal(stdout, &outputI)
|
||||||
|
if err != nil {
|
||||||
|
res.Err = e.UncallableController
|
||||||
|
return *res
|
||||||
|
}
|
||||||
|
|
||||||
|
output, ok := outputI.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
res.Err = e.UncallableController
|
||||||
|
return *res
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Err = e.Success
|
||||||
|
|
||||||
|
// extract error (success by default or on error)
|
||||||
|
if outErr, ok := output["error"]; ok {
|
||||||
|
errCode, ok := outErr.(float64)
|
||||||
|
if ok {
|
||||||
|
res.Err = e.Error{Code: int(errCode), Reason: "unknown reason", Arguments: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(output, "error")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (4) fill response */
|
||||||
|
for k, v := range output {
|
||||||
|
res.Set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *res
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (path GenericController) Post(d response.Arguments) response.Response {
|
||||||
|
return path.Get(d)
|
||||||
|
}
|
||||||
|
func (path GenericController) Put(d response.Arguments) response.Response {
|
||||||
|
return path.Get(d)
|
||||||
|
}
|
||||||
|
func (path GenericController) Delete(d response.Arguments) response.Response {
|
||||||
|
return path.Get(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenericMiddleware is the mockup for returning a middleware as a string (its path)
|
||||||
|
type GenericMiddleware string
|
||||||
|
|
||||||
|
func (path GenericMiddleware) Inspect(_req http.Request, _scope *[]string) {
|
||||||
|
|
||||||
|
/* (1) Prepare stdin data */
|
||||||
|
stdin, err := json.Marshal(_scope)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Try to load command with <stdin> -> stdout */
|
||||||
|
cmd := exec.Command(string(path), string(stdin))
|
||||||
|
|
||||||
|
stdout, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (3) Get output json */
|
||||||
|
var outputI interface{}
|
||||||
|
err = json.Unmarshal(stdout, &outputI)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (4) Get as []string */
|
||||||
|
scope, ok := outputI.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (5) Try to add each value to the scope */
|
||||||
|
for _, v := range scope {
|
||||||
|
stringScope, ok := v.(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
*_scope = append(*_scope, stringScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenericChecker is the mockup for returning a checker as a string (its path)
|
||||||
|
type GenericChecker string
|
||||||
|
|
||||||
|
func (path GenericChecker) Match(_type string) bool {
|
||||||
|
|
||||||
|
/* (1) Try to load command with <stdin> -> stdout */
|
||||||
|
cmd := exec.Command(string(path), _type)
|
||||||
|
|
||||||
|
stdout, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Parse output */
|
||||||
|
output := strings.ToLower(strings.Trim(string(stdout), " \t\r\n"))
|
||||||
|
|
||||||
|
return output == "true" || output == "1"
|
||||||
|
|
||||||
|
}
|
||||||
|
func (path GenericChecker) Check(_value interface{}) bool {
|
||||||
|
|
||||||
|
/* (1) Prepare stdin data */
|
||||||
|
indata := make(map[string]interface{})
|
||||||
|
indata["value"] = _value
|
||||||
|
|
||||||
|
stdin, err := json.Marshal(indata)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Try to load command with <stdin> -> stdout */
|
||||||
|
cmd := exec.Command(string(path), string(stdin))
|
||||||
|
|
||||||
|
stdout, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (2) Parse output */
|
||||||
|
output := strings.ToLower(strings.Trim(string(stdout), " \t\r\n"))
|
||||||
|
|
||||||
|
return output == "true" || output == "1"
|
||||||
|
|
||||||
|
}
|
140
driver/plugin.go
140
driver/plugin.go
|
@ -2,12 +2,8 @@ package driver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.xdrm.io/go/aicra/err"
|
|
||||||
"git.xdrm.io/go/aicra/response"
|
|
||||||
"net/http"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"plugin"
|
"plugin"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Plugin tells the aicra instance to use the plugin driver to load controller/middleware executables
|
// Plugin tells the aicra instance to use the plugin driver to load controller/middleware executables
|
||||||
|
@ -34,104 +30,88 @@ func (d Plugin) Path(_root, _folder, _src string) string {
|
||||||
|
|
||||||
// Source returns the source path from the universal path
|
// Source returns the source path from the universal path
|
||||||
func (d Plugin) Source(_root, _folder, _path string) string {
|
func (d Plugin) Source(_root, _folder, _path string) string {
|
||||||
|
|
||||||
return filepath.Join(_root, _folder, _path, "main.go")
|
return filepath.Join(_root, _folder, _path, "main.go")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build returns the build path from the universal path
|
// Build returns the build path from the universal path
|
||||||
func (d Plugin) Build(_root, _folder, _path string) string {
|
func (d Plugin) Build(_root, _folder, _path string) string {
|
||||||
|
if _path == "" {
|
||||||
|
return fmt.Sprintf("%s", filepath.Join(_root, ".build", _folder, "ROOT.so"))
|
||||||
|
}
|
||||||
return fmt.Sprintf("%s.so", filepath.Join(_root, ".build", _folder, _path))
|
return fmt.Sprintf("%s.so", filepath.Join(_root, ".build", _folder, _path))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compiled returns whether the driver has to be build
|
// Compiled returns whether the driver has to be build
|
||||||
func (d Plugin) Compiled() bool { return true }
|
func (d Plugin) Compiled() bool { return true }
|
||||||
|
|
||||||
// RunController implements the Driver interface
|
// LoadController returns a new Controller
|
||||||
func (d *Plugin) RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error) {
|
func (d *Plugin) LoadController(_path string) (Controller, error) {
|
||||||
|
|
||||||
/* (1) Build controller path */
|
/* 1. Try to load plugin */
|
||||||
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)
|
p, err := plugin.Open(_path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (4) Extract exported fields */
|
/* 2. Try to extract exported field */
|
||||||
mw, err := p.Lookup("Export")
|
m, err := p.Lookup("Export")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Missing method 'Inspect()'; %s", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
exported, ok := mw.(func() Middleware)
|
exporter, ok := m.(func() Controller)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("Inspect() is malformed")
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (5) Return Inspect method */
|
/* 3. Controller */
|
||||||
return exported().Inspect, nil
|
return exporter(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadMiddleware returns a new Middleware
|
||||||
|
func (d *Plugin) LoadMiddleware(_path string) (Middleware, error) {
|
||||||
|
|
||||||
|
/* 1. Try to load plugin */
|
||||||
|
p, err := plugin.Open(_path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Try to extract exported field */
|
||||||
|
m, err := p.Lookup("Export")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
exporter, ok := m.(func() Middleware)
|
||||||
|
if !ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return exporter(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadChecker returns a new Checker
|
||||||
|
func (d *Plugin) LoadChecker(_path string) (Checker, error) {
|
||||||
|
|
||||||
|
/* 1. Try to load plugin */
|
||||||
|
p, err := plugin.Open(_path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. Try to extract exported field */
|
||||||
|
m, err := p.Lookup("Export")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
exporter, ok := m.(func() Checker)
|
||||||
|
if !ok {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return exporter(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package driver
|
package driver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.xdrm.io/go/aicra/err"
|
|
||||||
"git.xdrm.io/go/aicra/response"
|
"git.xdrm.io/go/aicra/response"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
@ -14,8 +13,15 @@ type Driver interface {
|
||||||
Build(string, string, string) string
|
Build(string, string, string) string
|
||||||
Compiled() bool
|
Compiled() bool
|
||||||
|
|
||||||
RunController(_path []string, _method string) (func(response.Arguments) response.Response, err.Error)
|
LoadController(_path string) (Controller, error)
|
||||||
LoadMiddleware(_path string) (func(http.Request, *[]string), error)
|
LoadMiddleware(_path string) (Middleware, error)
|
||||||
|
LoadChecker(_path string) (Checker, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checker is the interface that type checkers implementation must follow
|
||||||
|
type Checker interface {
|
||||||
|
Match(string) bool
|
||||||
|
Check(interface{}) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controller is the interface that controller implementation must follow
|
// Controller is the interface that controller implementation must follow
|
||||||
|
|
|
@ -2,104 +2,20 @@ package checker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"git.xdrm.io/go/aicra/driver"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"plugin"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNoMatchingType = errors.New("no matching type")
|
var ErrNoMatchingType = errors.New("no matching type")
|
||||||
var ErrDoesNotMatch = errors.New("does not match")
|
var ErrDoesNotMatch = errors.New("does not match")
|
||||||
var ErrEmptyTypeName = errors.New("type name must not be empty")
|
|
||||||
|
|
||||||
// CreateRegistry creates an empty type registry
|
// CreateRegistry creates an empty type registry
|
||||||
func CreateRegistry(_folder string) *Registry {
|
func CreateRegistry() Registry {
|
||||||
|
return make(Registry)
|
||||||
/* (1) Create registry */
|
|
||||||
reg := &Registry{
|
|
||||||
Types: make([]Type, 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (2) List types */
|
|
||||||
files, err := ioutil.ReadDir(_folder)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Else try to load each given default */
|
|
||||||
for _, file := range files {
|
|
||||||
|
|
||||||
// ignore non .so files
|
|
||||||
if !strings.HasSuffix(file.Name(), ".so") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err := reg.add(file.Name())
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("cannot load plugin '%s'", file.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return reg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add adds a type to the registry; it must be a
|
// Add adds a new checker for a path
|
||||||
// valid and existing plugin name with or without the .so extension
|
func (reg Registry) Add(_path string, _element driver.Checker) {
|
||||||
// it must be located in the relative directory ./types
|
reg[_path] = _element
|
||||||
func (reg *Registry) add(pluginName string) error {
|
|
||||||
|
|
||||||
/* (1) Check plugin name */
|
|
||||||
if len(pluginName) < 1 {
|
|
||||||
return ErrEmptyTypeName
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (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/type/%s", pluginName))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (5) Export wanted properties */
|
|
||||||
matcher, err := p.Lookup("Match")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Missing method 'Match()'; %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
checker, err := p.Lookup("Check")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Missing method 'Check()'; %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (6) Cast Match+Check */
|
|
||||||
matcherCast, ok := matcher.(func(string) bool)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("Match() is malformed")
|
|
||||||
}
|
|
||||||
|
|
||||||
checkerCast, ok := checker.(func(interface{}) bool)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("Check() is malformed")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (7) Add type to registry */
|
|
||||||
reg.Types = append(reg.Types, Type{
|
|
||||||
Match: matcherCast,
|
|
||||||
Check: checkerCast,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run finds a type checker from the registry matching the type @typeName
|
// Run finds a type checker from the registry matching the type @typeName
|
||||||
|
@ -107,28 +23,23 @@ func (reg *Registry) add(pluginName string) error {
|
||||||
// the @typeName name, error is returned by default.
|
// the @typeName name, error is returned by default.
|
||||||
func (reg Registry) Run(typeName string, value interface{}) error {
|
func (reg Registry) Run(typeName string, value interface{}) error {
|
||||||
|
|
||||||
var T *Type
|
|
||||||
|
|
||||||
/* (1) Iterate to find matching type (take first) */
|
/* (1) Iterate to find matching type (take first) */
|
||||||
for _, t := range reg.Types {
|
for _, t := range reg {
|
||||||
|
|
||||||
// stop if found
|
// stop if found
|
||||||
if t.Match(typeName) {
|
if t.Match(typeName) {
|
||||||
T = &t
|
|
||||||
break
|
// check value
|
||||||
|
if t.Check(value) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrDoesNotMatch
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (2) Abort if no matching type */
|
return ErrNoMatchingType
|
||||||
if T == nil {
|
|
||||||
return ErrNoMatchingType
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Check */
|
|
||||||
if !T.Check(value) {
|
|
||||||
return ErrDoesNotMatch
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package checker
|
package checker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.xdrm.io/go/aicra/driver"
|
||||||
|
)
|
||||||
|
|
||||||
// Matcher returns whether a type 'name' matches a type
|
// Matcher returns whether a type 'name' matches a type
|
||||||
type Matcher func(name string) bool
|
type Matcher func(name string) bool
|
||||||
|
|
||||||
|
@ -8,15 +12,6 @@ type Matcher func(name string) bool
|
||||||
// to provide indulgent type check if needed
|
// to provide indulgent type check if needed
|
||||||
type Checker func(value interface{}) bool
|
type Checker func(value interface{}) bool
|
||||||
|
|
||||||
// Type contains all necessary methods
|
|
||||||
// for a type provided by user/developer
|
|
||||||
type Type struct {
|
|
||||||
Match func(string) bool
|
|
||||||
Check func(interface{}) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Registry represents a registry containing all available
|
// Registry represents a registry containing all available
|
||||||
// Type-s to be used by the framework according to the configuration
|
// Type-s to be used by the framework according to the configuration
|
||||||
type Registry struct {
|
type Registry map[string]driver.Checker
|
||||||
Types []Type // registered Type-s
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,19 +7,15 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// format inits the map if not set
|
|
||||||
func (b *builder) format() {
|
|
||||||
|
|
||||||
if b.Map == nil {
|
|
||||||
b.Map = make(map[string]string)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// InferFromFolder fills the 'Map' by browsing recursively the
|
// InferFromFolder fills the 'Map' by browsing recursively the
|
||||||
// 'Folder' field
|
// 'Folder' field
|
||||||
func (b *builder) InferFromFolder(_root string, _driver driver.Driver) {
|
func (b *builder) InferFromFolder(_root string, _driver driver.Driver) {
|
||||||
|
|
||||||
|
// init map
|
||||||
|
if b.Map == nil {
|
||||||
|
b.Map = make(map[string]string)
|
||||||
|
}
|
||||||
|
|
||||||
// 1. ignore if no Folder
|
// 1. ignore if no Folder
|
||||||
if len(b.Folder) < 1 {
|
if len(b.Folder) < 1 {
|
||||||
return
|
return
|
||||||
|
@ -46,10 +42,10 @@ func (b *builder) InferFromFolder(_root string, _driver driver.Driver) {
|
||||||
|
|
||||||
// format name
|
// format name
|
||||||
name := upath
|
name := upath
|
||||||
if name == "ROOT" {
|
if name == "/" {
|
||||||
name = ""
|
name = ""
|
||||||
}
|
}
|
||||||
name = fmt.Sprintf("/%s", name)
|
name = fmt.Sprintf("%s", name)
|
||||||
|
|
||||||
// add to map
|
// add to map
|
||||||
b.Map[name] = upath
|
b.Map[name] = upath
|
||||||
|
|
|
@ -2,22 +2,20 @@ package config
|
||||||
|
|
||||||
// Default contains the default values when ommited in json
|
// Default contains the default values when ommited in json
|
||||||
var Default = Schema{
|
var Default = Schema{
|
||||||
|
Root: ".",
|
||||||
Host: "0.0.0.0",
|
Host: "0.0.0.0",
|
||||||
Port: 80,
|
Port: 80,
|
||||||
DriverName: "",
|
DriverName: "",
|
||||||
Types: &builder{
|
Types: &builder{
|
||||||
Default: true,
|
Default: true,
|
||||||
Folder: "",
|
Folder: "type",
|
||||||
Map: nil,
|
|
||||||
},
|
},
|
||||||
Controllers: &builder{
|
Controllers: &builder{
|
||||||
Default: false,
|
Default: false,
|
||||||
Folder: "",
|
Folder: "controller",
|
||||||
Map: nil,
|
|
||||||
},
|
},
|
||||||
Middlewares: &builder{
|
Middlewares: &builder{
|
||||||
Default: false,
|
Default: false,
|
||||||
Folder: "",
|
Folder: "middleware",
|
||||||
Map: nil,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,7 @@ func Parse(_path string) (*Schema, error) {
|
||||||
return nil, errors.New("invalid driver; choose from 'generic', 'plugin'")
|
return nil, errors.New("invalid driver; choose from 'generic', 'plugin'")
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 5. Fail if type map is set */
|
/* 5. Fail on absolute folders */
|
||||||
if receiver.Types.Map != nil {
|
|
||||||
return nil, errors.New("types must not feature the 'map'")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 6. Fail on absolute folders */
|
|
||||||
if len(receiver.Types.Folder) > 0 && filepath.IsAbs(receiver.Types.Folder) {
|
if len(receiver.Types.Folder) > 0 && filepath.IsAbs(receiver.Types.Folder) {
|
||||||
return nil, errors.New("types folder must be relative to root")
|
return nil, errors.New("types folder must be relative to root")
|
||||||
}
|
}
|
||||||
|
@ -83,7 +78,7 @@ func (m *Schema) setDefaults() {
|
||||||
m.Port = Default.Port
|
m.Port = Default.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Empty builders
|
// 4. Use default builders if not set
|
||||||
if m.Types == nil {
|
if m.Types == nil {
|
||||||
m.Types = Default.Types
|
m.Types = Default.Types
|
||||||
}
|
}
|
||||||
|
@ -94,10 +89,16 @@ func (m *Schema) setDefaults() {
|
||||||
m.Middlewares = Default.Middlewares
|
m.Middlewares = Default.Middlewares
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Init map if not set
|
// 5. Use default folders if not set
|
||||||
m.Types.format()
|
if m.Types.Folder == "" {
|
||||||
m.Controllers.format()
|
m.Types.Folder = Default.Types.Folder
|
||||||
m.Middlewares.format()
|
}
|
||||||
|
if m.Controllers.Folder == "" {
|
||||||
|
m.Controllers.Folder = Default.Controllers.Folder
|
||||||
|
}
|
||||||
|
if m.Middlewares.Folder == "" {
|
||||||
|
m.Middlewares.Folder = Default.Middlewares.Folder
|
||||||
|
}
|
||||||
|
|
||||||
// 6. Infer Maps from Folders
|
// 6. Infer Maps from Folders
|
||||||
m.Types.InferFromFolder(m.Root, m.Driver)
|
m.Types.InferFromFolder(m.Root, m.Driver)
|
||||||
|
|
|
@ -12,13 +12,13 @@ type builder struct {
|
||||||
Folder string `json:"folder,ommitempty"`
|
Folder string `json:"folder,ommitempty"`
|
||||||
|
|
||||||
// Map defines the association path=>file
|
// Map defines the association path=>file
|
||||||
Map map[string]string `json:"map,ommitempty"`
|
Map map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schema represents an AICRA configuration (not the API, the server, drivers, etc)
|
// Schema represents an AICRA configuration (not the API, the server, drivers, etc)
|
||||||
type Schema struct {
|
type Schema struct {
|
||||||
// Root is root of the project structure
|
// Root is root of the project structure default is "." (current directory)
|
||||||
Root string `json:"root"`
|
Root string `json:"root,ommitempty"`
|
||||||
|
|
||||||
// Host is the hostname to listen to (default is 0.0.0.0)
|
// Host is the hostname to listen to (default is 0.0.0.0)
|
||||||
Host string `json:"host,ommitempty"`
|
Host string `json:"host,ommitempty"`
|
||||||
|
@ -26,28 +26,24 @@ type Schema struct {
|
||||||
Port uint16 `json:"port,ommitempty"`
|
Port uint16 `json:"port,ommitempty"`
|
||||||
|
|
||||||
// DriverName is the driver used to load the controllers and middlewares
|
// DriverName is the driver used to load the controllers and middlewares
|
||||||
// (default is 'plugin')
|
|
||||||
DriverName string `json:"driver"`
|
DriverName string `json:"driver"`
|
||||||
Driver driver.Driver
|
Driver driver.Driver
|
||||||
|
|
||||||
// Types defines :
|
// Types defines :
|
||||||
// - the type folder
|
// - the type folder
|
||||||
// - each type by 'name => path'
|
|
||||||
// - whether to load the built-in types
|
// - whether to load the built-in types
|
||||||
//
|
//
|
||||||
// types are ommited if not set (no default)
|
// types are ommited if not set (no default)
|
||||||
Types *builder `json:"types,ommitempty"`
|
Types *builder `json:"types,ommitempty"`
|
||||||
|
|
||||||
// Controllers defines :
|
// Controllers defines :
|
||||||
// - the controller folder (as a single string)
|
// - the controller folder
|
||||||
// - each controller by 'name => path' (as a map)
|
|
||||||
//
|
//
|
||||||
// (default is .build/controller)
|
// (default is .build/controller)
|
||||||
Controllers *builder `json:"controllers,ommitempty"`
|
Controllers *builder `json:"controllers,ommitempty"`
|
||||||
|
|
||||||
// Middlewares defines :
|
// Middlewares defines :
|
||||||
// - the middleware folder (as a single string)
|
// - the middleware folder
|
||||||
// - each middleware by 'name => path' (as a map)
|
|
||||||
//
|
//
|
||||||
// (default is .build/middleware)
|
// (default is .build/middleware)
|
||||||
Middlewares *builder `json:"middlewares,ommitempty"`
|
Middlewares *builder `json:"middlewares,ommitempty"`
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
package request
|
package request
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.xdrm.io/go/aicra/driver"
|
|
||||||
"git.xdrm.io/go/aicra/err"
|
|
||||||
"git.xdrm.io/go/aicra/response"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -27,11 +24,3 @@ func FromHTTP(req *http.Request) (*Request, error) {
|
||||||
|
|
||||||
return inst, nil
|
return inst, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunController tries to load a controller from its uri
|
|
||||||
// checks for its given method ('Get', 'Post', 'Put', or 'Delete')
|
|
||||||
func (i *Request) RunController(_method string, _driver driver.Driver) (func(response.Arguments) response.Response, err.Error) {
|
|
||||||
|
|
||||||
return _driver.RunController(i.Path, _method)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,38 +2,17 @@ package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.xdrm.io/go/aicra/driver"
|
"git.xdrm.io/go/aicra/driver"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateRegistry creates an empty middleware registry
|
// CreateRegistry creates an empty registry
|
||||||
func CreateRegistry(_driver driver.Driver, _folder string) *Registry {
|
func CreateRegistry() Registry {
|
||||||
|
return make(Registry)
|
||||||
|
}
|
||||||
|
|
||||||
/* (1) Create registry */
|
// Add adds a new middleware for a path
|
||||||
reg := &Registry{
|
func (reg Registry) Add(_path string, _element driver.Middleware) {
|
||||||
Middlewares: make([]*Wrapper, 0),
|
reg[_path] = _element
|
||||||
}
|
|
||||||
|
|
||||||
/* (2) List middleware files */
|
|
||||||
files, err := ioutil.ReadDir(_folder)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (3) Else try to load each given default */
|
|
||||||
for _, file := range files {
|
|
||||||
|
|
||||||
mwFunc, err := _driver.LoadMiddleware(path.Join(_folder, file.Name()))
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("cannot load middleware '%s' | %s", file.Name(), err)
|
|
||||||
}
|
|
||||||
reg.Middlewares = append(reg.Middlewares, &Wrapper{Inspect: mwFunc})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return reg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run executes all middlewares (default browse order)
|
// Run executes all middlewares (default browse order)
|
||||||
|
@ -43,8 +22,8 @@ func (reg Registry) Run(req http.Request) []string {
|
||||||
scope := make([]string, 0)
|
scope := make([]string, 0)
|
||||||
|
|
||||||
/* (2) Execute each middleware */
|
/* (2) Execute each middleware */
|
||||||
for _, m := range reg.Middlewares {
|
for _, mw := range reg {
|
||||||
m.Inspect(req, &scope)
|
mw.Inspect(req, &scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
return scope
|
return scope
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"git.xdrm.io/go/aicra/driver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scope represents a list of scope processed by middlewares
|
// Scope represents a list of scope processed by middlewares
|
||||||
|
@ -12,13 +12,7 @@ import (
|
||||||
// purposes, the type is always used as its definition ([]string)
|
// purposes, the type is always used as its definition ([]string)
|
||||||
type Scope []string
|
type Scope []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 {
|
// The map is <name> => <middleware>
|
||||||
Middlewares []*Wrapper
|
type Registry map[string]driver.Middleware
|
||||||
}
|
|
||||||
|
|
98
server.go
98
server.go
|
@ -7,8 +7,10 @@ import (
|
||||||
"git.xdrm.io/go/aicra/internal/config"
|
"git.xdrm.io/go/aicra/internal/config"
|
||||||
apirequest "git.xdrm.io/go/aicra/internal/request"
|
apirequest "git.xdrm.io/go/aicra/internal/request"
|
||||||
"git.xdrm.io/go/aicra/middleware"
|
"git.xdrm.io/go/aicra/middleware"
|
||||||
|
"git.xdrm.io/go/aicra/response"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server represents an AICRA instance featuring:
|
// Server represents an AICRA instance featuring:
|
||||||
|
@ -16,9 +18,9 @@ import (
|
||||||
// * its middlewares
|
// * its middlewares
|
||||||
// * its controllers (api config)
|
// * its controllers (api config)
|
||||||
type Server struct {
|
type Server struct {
|
||||||
controller *api.Controller // controllers
|
controller *api.Controller // controllers
|
||||||
checker *checker.Registry // type checker registry
|
checker checker.Registry // type checker registry
|
||||||
middleware *middleware.Registry // middlewares
|
middleware middleware.Registry // middlewares
|
||||||
schema *config.Schema
|
schema *config.Schema
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,32 +36,47 @@ func New(_path string) (*Server, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2. Default driver : Plugin */
|
/* 2. Init instance */
|
||||||
_folders := make([]string, 0, 2)
|
|
||||||
_folders = append(_folders, ".build/type")
|
|
||||||
if schema.Driver.Name() == "plugin" { // plugin
|
|
||||||
_folders = append(_folders, ".build/middleware")
|
|
||||||
} else { // generic
|
|
||||||
_folders = append(_folders, "middleware")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (1) Init instance */
|
|
||||||
var i = &Server{
|
var i = &Server{
|
||||||
controller: nil,
|
controller: nil,
|
||||||
schema: schema,
|
schema: schema,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (2) Load configuration */
|
/* 3. Load configuration */
|
||||||
i.controller, err = api.Parse(_path)
|
i.controller, err = api.Parse(_path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (3) Default type registry */
|
/* 4. Load type registry */
|
||||||
i.checker = checker.CreateRegistry(_folders[0])
|
i.checker = checker.CreateRegistry()
|
||||||
|
|
||||||
/* (4) Default middleware registry */
|
// add default types if set
|
||||||
i.middleware = middleware.CreateRegistry(schema.Driver, _folders[1])
|
|
||||||
|
// add custom types
|
||||||
|
for name, path := range schema.Types.Map {
|
||||||
|
|
||||||
|
fullpath := schema.Driver.Build(schema.Root, schema.Types.Folder, path)
|
||||||
|
mwFunc, err := schema.Driver.LoadChecker(fullpath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("cannot load type checker '%s' | %s", name, err)
|
||||||
|
}
|
||||||
|
i.checker.Add(path, mwFunc)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5. Load middleware registry */
|
||||||
|
i.middleware = middleware.CreateRegistry()
|
||||||
|
for name, path := range schema.Middlewares.Map {
|
||||||
|
|
||||||
|
fullpath := schema.Driver.Build(schema.Root, schema.Middlewares.Folder, path)
|
||||||
|
mwFunc, err := schema.Driver.LoadMiddleware(fullpath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("cannot load middleware '%s' | %s", name, err)
|
||||||
|
}
|
||||||
|
i.middleware.Add(path, mwFunc)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return i, nil
|
return i, nil
|
||||||
|
|
||||||
|
@ -109,25 +126,52 @@ func (s *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
/* (5) Load controller
|
/* (5) Load controller
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
controllerImplementation, callErr := apiRequest.RunController(req.Method, s.schema.Driver)
|
// get paths
|
||||||
if callErr.Code != e.Success.Code {
|
ctlBuildPath := strings.Join(apiRequest.Path, "/")
|
||||||
httpError(res, callErr)
|
ctlBuildPath = s.schema.Driver.Build(s.schema.Root, s.schema.Controllers.Folder, ctlBuildPath)
|
||||||
log.Printf("[err] %s\n", err)
|
|
||||||
|
// get controller
|
||||||
|
ctlObject, err := s.schema.Driver.LoadController(ctlBuildPath)
|
||||||
|
httpMethod := strings.ToUpper(req.Method)
|
||||||
|
if err != nil {
|
||||||
|
httpErr := e.UncallableController
|
||||||
|
httpErr.BindArgument(err)
|
||||||
|
httpError(res, httpErr)
|
||||||
|
log.Printf("err( %s )\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctlMethod func(response.Arguments) response.Response
|
||||||
|
// select method
|
||||||
|
switch httpMethod {
|
||||||
|
case "GET":
|
||||||
|
ctlMethod = ctlObject.Get
|
||||||
|
case "POST":
|
||||||
|
ctlMethod = ctlObject.Post
|
||||||
|
case "PUT":
|
||||||
|
ctlMethod = ctlObject.Put
|
||||||
|
case "DELETE":
|
||||||
|
ctlMethod = ctlObject.Delete
|
||||||
|
default:
|
||||||
|
httpError(res, e.UnknownMethod)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (6) Execute and get response
|
/* (6) Execute and get response
|
||||||
---------------------------------------------------------*/
|
---------------------------------------------------------*/
|
||||||
/* (1) Give Authorization header into controller */
|
/* (1) Give HTTP METHOD */
|
||||||
|
parameters["_HTTP_METHOD_"] = httpMethod
|
||||||
|
|
||||||
|
/* (2) Give Authorization header into controller */
|
||||||
parameters["_AUTHORIZATION_"] = req.Header.Get("Authorization")
|
parameters["_AUTHORIZATION_"] = req.Header.Get("Authorization")
|
||||||
|
|
||||||
/* (2) Give Scope into controller */
|
/* (3) Give Scope into controller */
|
||||||
parameters["_SCOPE_"] = scope
|
parameters["_SCOPE_"] = scope
|
||||||
|
|
||||||
/* (3) Execute */
|
/* (4) Execute */
|
||||||
response := controllerImplementation(parameters)
|
response := ctlMethod(parameters)
|
||||||
|
|
||||||
/* (4) Extract http headers */
|
/* (5) Extract http headers */
|
||||||
for k, v := range response.Dump() {
|
for k, v := range response.Dump() {
|
||||||
if k == "_REDIRECT_" {
|
if k == "_REDIRECT_" {
|
||||||
if newLocation, ok := v.(string); ok {
|
if newLocation, ok := v.(string); ok {
|
||||||
|
|
Loading…
Reference in New Issue