diff --git a/cmd/aicra/main.go b/cmd/aicra/main.go index 441a5ad..f0d7f87 100644 --- a/cmd/aicra/main.go +++ b/cmd/aicra/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" "git.xdrm.io/go/aicra/internal/clifmt" - "git.xdrm.io/go/aicra/internal/meta" + "git.xdrm.io/go/aicra/internal/config" "os" "path/filepath" "time" @@ -16,7 +16,7 @@ func main() { starttime := time.Now() /* 1. Load config */ - schema, err := meta.Parse("./aicra.json") + schema, err := config.Parse("./aicra.json") if err != nil { fmt.Printf("aicra.json: %s\n", err) return diff --git a/driver/generic.go b/driver/generic.go index b124461..c2728ab 100644 --- a/driver/generic.go +++ b/driver/generic.go @@ -11,6 +11,13 @@ import ( "strings" ) +// 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 +type Generic struct{} + // Name returns the driver name func (d *Generic) Name() string { return "generic" } diff --git a/driver/import.go b/driver/import.go deleted file mode 100644 index 52d0417..0000000 --- a/driver/import.go +++ /dev/null @@ -1,132 +0,0 @@ -package driver - -import ( - "errors" - "fmt" - e "git.xdrm.io/go/aicra/err" - "git.xdrm.io/go/aicra/response" - "net/http" - "path/filepath" - "strings" -) - -// Name returns the driver name -func (d *Import) Name() string { return "import" } - -// Path returns the universal path from the source path -func (d Import) Path(_root, _folder, _src string) string { - return strings.TrimSuffix(_src, ".go") -} - -// Source returns the source path from the universal path -func (d Import) Source(_root, _folder, _path string) string { - return fmt.Sprintf("%s.go", filepath.Join(_root, _folder, _path)) - -} - -// Build returns the build path from the universal path -func (d Import) Build(_root, _folder, _path string) string { - return filepath.Join(_root, _folder, _path) -} - -// Compiled returns whether the driver has to be build -func (d Import) Compiled() bool { return false } - -// RegisterController registers a new controller -func (d *Import) RegisterController(_path string, _controller Controller) error { - - // 1. init controllers if not already - if d.Controllers == nil { - d.Controllers = make(map[string]Controller) - } - - // 2. fail if no controller - if _controller == nil { - return errors.New("nil controller") - } - - // 3. Fail on invalid path - if len(_path) < 1 || _path[0] != '/' { - return errors.New("invalid controller path") - } - - // 4. Store controller - d.Controllers[_path] = _controller - return nil - -} - -// RegisterMiddleware registers a new controller -func (d *Import) RegisterMiddlware(_path string, _middleware Middleware) error { - - // 1. init imddlewares if not already - if d.Middlewares == nil { - d.Middlewares = make(map[string]Middleware) - } - - // 2. fail if no imddleware - if _middleware == nil { - return errors.New("nil imddleware") - } - - // 3. Fail on invalid path - if len(_path) < 1 || _path[0] != '/' { - return errors.New("invalid imddleware path") - } - - // 4. Store imddleware - d.Middlewares[_path] = _middleware - return nil - -} - -// RunController implements the Driver interface -func (d *Import) RunController(_path []string, _method string) (func(response.Arguments) response.Response, e.Error) { - - /* (1) Build controller path */ - path := strings.Join(_path, "-") - - /* (2) Check if controller exists */ - controller, ok := d.Controllers[path] - if !ok { - return nil, e.UncallableController - } - - /* (3) Format method */ - method := strings.ToLower(_method) - - /* (4) Return method according to method */ - switch method { - case "GET": - return controller.Get, e.Success - case "POST": - return controller.Post, e.Success - case "PUT": - return controller.Put, e.Success - case "DELETE": - return controller.Delete, e.Success - default: - return nil, e.UncallableMethod - } - - return nil, e.UncallableController -} - -// LoadMiddleware returns a new middleware function; it must be a -// valid and existing folder/filename file with the .so extension -func (d *Import) LoadMiddleware(_path string) (func(http.Request, *[]string), error) { - - /* (1) Check plugin name */ - if len(_path) < 1 { - return nil, errors.New("middleware name must not be empty") - } - - /* (2) Check if middleware exists */ - middleware, ok := d.Middlewares[_path] - if !ok { - return nil, errors.New("middleware not found") - } - - /* (3) Return middleware */ - return middleware.Inspect, nil -} diff --git a/driver/plugin.go b/driver/plugin.go index ca0e600..baac40b 100644 --- a/driver/plugin.go +++ b/driver/plugin.go @@ -10,6 +10,20 @@ import ( "strings" ) +// 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 : +// +// type Controller 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 +// } +// +// The controllers are exported by calling the 'Export() Controller' method +type Plugin struct{} + // Name returns the driver name func (d Plugin) Name() string { return "plugin" } diff --git a/driver/types.go b/driver/types.go index 7062e25..593f067 100644 --- a/driver/types.go +++ b/driver/types.go @@ -18,18 +18,6 @@ type Driver interface { LoadMiddleware(_path string) (func(http.Request, *[]string), error) } -// 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 -// -// CONTROLLER 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{} - // Controller is the interface that controller implementation must follow // it is used by the 'Import' driver type Controller interface { @@ -44,64 +32,3 @@ type Controller interface { type Middleware interface { Inspect(http.Request, *[]string) } - -// Import tells the aicra instance to use the import driver to load controller/middleware executables -// -// It will compile imported with the following interface : -// -// type Controller interface { -// Get(d response.Arguments) response.Response -// Post(d response.Arguments) response.Response -// Put(d response.Arguments) response.Response -// Delete(d response.Arguments) response.Response -// } -// -// CONTROLLER FILE STRUCTURE -// -------------- -// - the root (/) controller executable must be named /controller/ROOT.go -// - the a/b/c controller executable must be named /controller/a/b/c.go -// -// COMPILATION -// ----------- -// The controllers/middlewares are imported and instanciated inside the main function, they are -// thus compiled with the main binary file -type Import struct { - Controllers map[string]Controller - Middlewares map[string]Middleware -} - -// 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 : -// -// 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 -// } -// -// CONTROLLER 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/middleware executables -// -// Warning: PHP only -// -// It will use the fastcgi protocol with php at : -// -// CONTROLLER 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/meta/builder.go b/internal/config/builder.go similarity index 98% rename from internal/meta/builder.go rename to internal/config/builder.go index 28d791a..ae6ec09 100644 --- a/internal/meta/builder.go +++ b/internal/config/builder.go @@ -1,4 +1,4 @@ -package meta +package config import ( "fmt" diff --git a/internal/meta/defaults.go b/internal/config/defaults.go similarity index 96% rename from internal/meta/defaults.go rename to internal/config/defaults.go index db23aea..a2b4913 100644 --- a/internal/meta/defaults.go +++ b/internal/config/defaults.go @@ -1,4 +1,4 @@ -package meta +package config // Default contains the default values when ommited in json var Default = Schema{ diff --git a/internal/meta/parser.go b/internal/config/parser.go similarity index 96% rename from internal/meta/parser.go rename to internal/config/parser.go index 14c054d..0478255 100644 --- a/internal/meta/parser.go +++ b/internal/config/parser.go @@ -1,4 +1,4 @@ -package meta +package config import ( "encoding/json" @@ -36,11 +36,9 @@ func Parse(_path string) (*Schema, error) { receiver.Driver = &driver.Generic{} case "plugin": receiver.Driver = &driver.Plugin{} - case "import": - receiver.Driver = &driver.Import{} default: - return nil, errors.New("invalid driver; choose from 'generic', 'plugin', and 'import'") + return nil, errors.New("invalid driver; choose from 'generic', 'plugin'") } /* 5. Fail if type map is set */ diff --git a/internal/meta/types.go b/internal/config/types.go similarity index 99% rename from internal/meta/types.go rename to internal/config/types.go index 53fcb98..53df2e7 100644 --- a/internal/meta/types.go +++ b/internal/config/types.go @@ -1,4 +1,4 @@ -package meta +package config import ( "git.xdrm.io/go/aicra/driver" diff --git a/internal/request/request.go b/internal/request/request.go index a02c710..16f51d5 100644 --- a/internal/request/request.go +++ b/internal/request/request.go @@ -1,15 +1,11 @@ package request 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" "strings" - "time" ) // FromHTTP builds an interface request from a http.Request @@ -32,66 +28,6 @@ func FromHTTP(req *http.Request) (*Request, error) { return inst, nil } -// FetchFormData extracts FORM data -// -// - parse 'form-data' if not supported (not POST requests) -// - parse 'x-www-form-urlencoded' -// - parse 'application/json' -func FetchFormData(req *http.Request) map[string]interface{} { - - res := make(map[string]interface{}) - - // Abort if GET request - if req.Method == "GET" { - return res - } - - ct := req.Header.Get("Content-Type") - - if strings.HasPrefix(ct, "application/json") { - - receiver := make(map[string]interface{}, 0) - - // 1. Init JSON reader - decoder := json.NewDecoder(req.Body) - if err := decoder.Decode(&receiver); err != nil { - log.Printf("[parse.json] %s\n", err) - return res - } - - // 2. Return result - return receiver - - } else if strings.HasPrefix(ct, "application/x-www-form-urlencoded") { - - // 1. Parse url encoded data - req.ParseForm() - - // 2. Extract values - for name, value := range req.PostForm { - res[name] = value - } - - } else { // form-data or anything - - startn := time.Now().UnixNano() - // 1. Parse form-data - if err := req.ParseMultipartForm(req.ContentLength + 1); err != nil { - log.Printf("[read.multipart] %s\n", err) - return res - } - - // 2. Extract values - for name, value := range req.PostForm { - res[name] = value - } - fmt.Printf("* %.3f us\n", float64(time.Now().UnixNano()-startn)/1e3) - - } - - return res -} - // 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) { diff --git a/server.go b/server.go index 1c2ae22..b820885 100644 --- a/server.go +++ b/server.go @@ -4,7 +4,7 @@ import ( e "git.xdrm.io/go/aicra/err" "git.xdrm.io/go/aicra/internal/api" "git.xdrm.io/go/aicra/internal/checker" - "git.xdrm.io/go/aicra/internal/meta" + "git.xdrm.io/go/aicra/internal/config" apirequest "git.xdrm.io/go/aicra/internal/request" "git.xdrm.io/go/aicra/middleware" "log" @@ -19,7 +19,7 @@ type Server struct { controller *api.Controller // controllers checker *checker.Registry // type checker registry middleware *middleware.Registry // middlewares - schema *meta.Schema + schema *config.Schema } // New creates a framework instance from a configuration file @@ -29,7 +29,7 @@ type Server struct { func New(_path string) (*Server, error) { /* 1. Load config */ - schema, err := meta.Parse("./aicra.json") + schema, err := config.Parse("./aicra.json") if err != nil { return nil, err }