diff --git a/driver/plugin.go b/driver/plugin.go new file mode 100644 index 0000000..7fff8f1 --- /dev/null +++ b/driver/plugin.go @@ -0,0 +1,46 @@ +package driver + +import ( + "fmt" + "git.xdrm.io/go/aicra/err" + "git.xdrm.io/go/aicra/response" + "plugin" + "strings" +) + +// Load implements the Driver interface +func (d *Plugin) Load(_path []string, _method string) (func(response.Arguments, *response.Response) 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 */ + tmp := []byte(strings.ToLower(_method)) + tmp[0] = tmp[0] - ('a' - 'A') + method := string(tmp) + + /* (2) Try to load plugin */ + p, err2 := plugin.Open(path) + if err2 != nil { + return nil, err.UncallableController + } + + /* (3) Try to extract method */ + m, err2 := p.Lookup(method) + if err2 != nil { + return nil, err.UncallableMethod + } + + /* (4) Check signature */ + callable, validSignature := m.(func(response.Arguments, *response.Response) response.Response) + if !validSignature { + return nil, err.UncallableMethod + } + + return callable, err.Success +} diff --git a/driver/types.go b/driver/types.go new file mode 100644 index 0000000..eec51ff --- /dev/null +++ b/driver/types.go @@ -0,0 +1,58 @@ +package driver + +import ( + "git.xdrm.io/go/aicra/err" + "git.xdrm.io/go/aicra/response" +) + +type Driver interface { + Load(_path []string, _method string) (func(response.Arguments, *response.Response) response.Response, err.Error) +} + +// Generic tells the aicra instance to use the generic driver to load controller's executables +// +// It will call an executable with the json input into the standard input +// 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 +// -------------- +// - the root (/) controller executable must be named /controller/ROOT +// - the a/b/c controller executable must be named /controller/a/b/c +type Generic struct{} + +// Plugin tells the aicra instance to use the plugin driver to load controller's executables +// +// It will load go .so plugins with the following interface : +// +// type Plugin interface { +// Get(d i.Arguments, r *i.Response) i.Response +// Post(d i.Arguments, r *i.Response) i.Response +// Put(d i.Arguments, r *i.Response) i.Response +// Delete(d i.Arguments, r *i.Response) i.Response +// } +// +// FILE STRUCTURE +// -------------- +// - the root (/) controller executable must be named /controller/ROOT/main.so +// - the a/b/c controller executable must be named /controller/a/b/c/main.so +// +// COMPILATION +// ----------- +// The compilation is handled with the command-line tool `aicra ` +type Plugin struct{} + +// FastCGI tells the aicra instance to use the fastcgi driver to load controller's executables +// +// Warning: PHP only +// +// It will use the fastcgi protocol with php at : +// +// FILE STRUCTURE +// -------------- +// - the root (/) controller executable must be named /controller/ROOT.php +// - the a/b/c controller executable must be named /controller/a/b/c.php +type FastCGI struct { + host string + port string +} diff --git a/internal/apirequest/request.go b/internal/apirequest/request.go index 3bf4426..e5e7612 100644 --- a/internal/apirequest/request.go +++ b/internal/apirequest/request.go @@ -3,11 +3,11 @@ package apirequest import ( "encoding/json" "fmt" + "git.xdrm.io/go/aicra/driver" "git.xdrm.io/go/aicra/err" "git.xdrm.io/go/aicra/response" "log" "net/http" - "plugin" "strings" "time" ) @@ -94,39 +94,8 @@ func FetchFormData(req *http.Request) map[string]interface{} { // LoadController tries to load a controller from its uri // checks for its given method ('Get', 'Post', 'Put', or 'Delete') -func (i *Request) LoadController(method string) (func(response.Arguments, *response.Response) response.Response, err.Error) { +func (i *Request) LoadController(_method string, _driver driver.Driver) (func(response.Arguments, *response.Response) response.Response, err.Error) { - /* (1) Build controller path */ - path := strings.Join(i.Path, "-") - if len(path) == 0 { - path = fmt.Sprintf(".build/controller/ROOT.so") - } else { - path = fmt.Sprintf(".build/controller/%s.so", path) - } - - /* (2) Format url */ - tmp := []byte(strings.ToLower(method)) - tmp[0] = tmp[0] - ('a' - 'A') - method = string(tmp) - - /* (2) Try to load plugin */ - p, err2 := plugin.Open(path) - if err2 != nil { - return nil, err.UncallableController - } - - /* (3) Try to extract method */ - m, err2 := p.Lookup(method) - if err2 != nil { - return nil, err.UncallableMethod - } - - /* (4) Check signature */ - callable, validSignature := m.(func(response.Arguments, *response.Response) response.Response) - if !validSignature { - return nil, err.UncallableMethod - } - - return callable, err.Success + return _driver.Load(i.Path, _method) } diff --git a/internal/controller/controller.go b/internal/config/controller.go similarity index 99% rename from internal/controller/controller.go rename to internal/config/controller.go index 849d3e3..3f4f512 100644 --- a/internal/controller/controller.go +++ b/internal/config/controller.go @@ -1,4 +1,4 @@ -package controller +package config import ( "encoding/json" diff --git a/internal/controller/method.go b/internal/config/method.go similarity index 97% rename from internal/controller/method.go rename to internal/config/method.go index 9d0d7b8..03fb08e 100644 --- a/internal/controller/method.go +++ b/internal/config/method.go @@ -1,4 +1,4 @@ -package controller +package config import ( "git.xdrm.io/go/aicra/middleware" diff --git a/internal/controller/types.go b/internal/config/types.go similarity index 97% rename from internal/controller/types.go rename to internal/config/types.go index 340d743..87f7bb6 100644 --- a/internal/controller/types.go +++ b/internal/config/types.go @@ -1,4 +1,4 @@ -package controller +package config /* (1) Configuration ---------------------------------------------------------*/ diff --git a/server.go b/server.go index eaf009a..6c24f05 100644 --- a/server.go +++ b/server.go @@ -1,10 +1,12 @@ package aicra import ( + "errors" + "git.xdrm.io/go/aicra/driver" e "git.xdrm.io/go/aicra/err" "git.xdrm.io/go/aicra/internal/apirequest" "git.xdrm.io/go/aicra/internal/checker" - "git.xdrm.io/go/aicra/internal/controller" + "git.xdrm.io/go/aicra/internal/config" "git.xdrm.io/go/aicra/middleware" "git.xdrm.io/go/aicra/response" "log" @@ -16,22 +18,30 @@ import ( // * its middlewares // * its controllers (config) type Server struct { - controller *controller.Controller // controllers - checker *checker.Registry // type checker registry - middleware *middleware.Registry // middlewares + controller *config.Controller // controllers + checker *checker.Registry // type checker registry + middleware *middleware.Registry // middlewares + driver driver.Driver } +var ErrNilDriver = errors.New("the driver is ") + // New creates a framework instance from a configuration file -func New(path string) (*Server, error) { +func New(_path string, _driver driver.Driver) (*Server, error) { + + if _driver == nil { + return nil, ErrNilDriver + } /* (1) Init instance */ var err error var i = &Server{ controller: nil, + driver: _driver, } /* (2) Load configuration */ - i.controller, err = controller.Load(path) + i.controller, err = config.Load(_path) if err != nil { return nil, err } @@ -90,7 +100,7 @@ func (s *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) { /* (5) Load controller ---------------------------------------------------------*/ - controllerImplementation, callErr := apiRequest.LoadController(req.Method) + controllerImplementation, callErr := apiRequest.LoadController(req.Method, s.driver) if callErr.Code != e.Success.Code { httpError(res, callErr) log.Printf("[err] %s\n", err) @@ -126,7 +136,7 @@ func (s *Server) ServeHTTP(res http.ResponseWriter, req *http.Request) { // extractParameters extracts parameters for the request and checks // every single one according to configuration options -func (s *Server) extractParameters(req *apirequest.Request, methodParam map[string]*controller.Parameter) (map[string]interface{}, e.Error) { +func (s *Server) extractParameters(req *apirequest.Request, methodParam map[string]*config.Parameter) (map[string]interface{}, e.Error) { // init vars err := e.Success diff --git a/util.go b/util.go index f27fbc9..92774d5 100644 --- a/util.go +++ b/util.go @@ -4,13 +4,13 @@ import ( "encoding/json" "git.xdrm.io/go/aicra/err" "git.xdrm.io/go/aicra/internal/apirequest" - "git.xdrm.io/go/aicra/internal/controller" + "git.xdrm.io/go/aicra/internal/config" "git.xdrm.io/go/aicra/response" "log" "net/http" ) -func (s *Server) matchController(req *apirequest.Request) *controller.Controller { +func (s *Server) matchController(req *apirequest.Request) *config.Controller { /* (1) Try to browse by URI */ pathi, ctl := s.controller.Browse(req.URI)