1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-08 20:41:57 +00:00
Former-commit-id: fe6305deed00e170bf4d39a12c0644fe686e0a24
This commit is contained in:
Gerasimos (Makis) Maropoulos
2018-10-21 19:20:05 +03:00
parent dbba631df4
commit 3962710d3d
109 changed files with 4383 additions and 2658 deletions

View File

@@ -7,9 +7,9 @@ import (
"github.com/kataras/iris/context"
"github.com/kataras/iris/core/router"
"github.com/kataras/iris/core/router/macro"
"github.com/kataras/iris/hero"
"github.com/kataras/iris/hero/di"
"github.com/kataras/iris/macro"
"github.com/kataras/golog"
)
@@ -247,7 +247,7 @@ func (c *ControllerActivator) parseMethods() {
}
func (c *ControllerActivator) parseMethod(m reflect.Method) {
httpMethod, httpPath, err := parseMethod(m, c.isReservedMethod)
httpMethod, httpPath, err := parseMethod(*c.router.Macros(), m, c.isReservedMethod)
if err != nil {
if err != errSkip {
c.addErr(fmt.Errorf("MVC: fail to parse the route path and HTTP method for '%s.%s': %v", c.fullName, m.Name, err))
@@ -283,7 +283,7 @@ func (c *ControllerActivator) Handle(method, path, funcName string, middleware .
}
// parse a route template which contains the parameters organised.
tmpl, err := macro.Parse(path, c.router.Macros())
tmpl, err := macro.Parse(path, *c.router.Macros())
if err != nil {
c.addErr(fmt.Errorf("MVC: fail to parse the path for '%s.%s': %v", c.fullName, funcName, err))
return nil
@@ -338,6 +338,7 @@ func (c *ControllerActivator) handlerOf(m reflect.Method, funcDependencies []ref
}
// fmt.Printf("for %s | values: %s\n", funcName, funcDependencies)
funcInjector := di.Func(m.Func, funcDependencies...)
// fmt.Printf("actual injector's inputs length: %d\n", funcInjector.Length)
if funcInjector.Has {
@@ -396,6 +397,11 @@ func (c *ControllerActivator) handlerOf(m reflect.Method, funcDependencies []ref
in := make([]reflect.Value, n, n)
in[0] = ctrl
funcInjector.Inject(&in, ctxValue)
// for idxx, inn := range in {
// println("controller.go: execution: in.Value = "+inn.String()+" and in.Type = "+inn.Type().Kind().String()+" of index: ", idxx)
// }
hero.DispatchFuncResult(ctx, call(in))
return
}

View File

@@ -37,6 +37,7 @@ type testControllerHandle struct {
func (c *testControllerHandle) BeforeActivation(b BeforeActivation) {
b.Handle("GET", "/histatic", "HiStatic")
b.Handle("GET", "/hiservice", "HiService")
b.Handle("GET", "/hiservice/{ps:string}", "HiServiceBy")
b.Handle("GET", "/hiparam/{ps:string}", "HiParamBy")
b.Handle("GET", "/hiparamempyinput/{ps:string}", "HiParamEmptyInputBy")
}
@@ -84,6 +85,10 @@ func (c *testControllerHandle) HiService() string {
return c.Service.Say("hi")
}
func (c *testControllerHandle) HiServiceBy(v string) string {
return c.Service.Say("hi with param: " + v)
}
func (c *testControllerHandle) HiParamBy(v string) string {
return v
}
@@ -116,7 +121,8 @@ func TestControllerHandle(t *testing.T) {
// and can be used in a user-defined, dynamic "mvc handler".
e.GET("/hiservice").Expect().Status(httptest.StatusOK).
Body().Equal("service: hi")
e.GET("/hiservice/value").Expect().Status(httptest.StatusOK).
Body().Equal("service: hi with param: value")
// this worked with a temporary variadic on the resolvemethodfunc which is not
// correct design, I should split the path and params with the rest of implementation
// in order a simple template.Src can be given.

View File

@@ -4,11 +4,12 @@ import (
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"unicode"
"github.com/kataras/iris/core/router"
"github.com/kataras/iris/core/router/macro/interpreter/ast"
"github.com/kataras/iris/macro"
)
const (
@@ -95,47 +96,25 @@ func (l *methodLexer) peekPrev() (w string) {
return w
}
var posWords = map[int]string{
0: "",
1: "first",
2: "second",
3: "third",
4: "forth",
5: "five",
6: "sixth",
7: "seventh",
8: "eighth",
9: "ninth",
10: "tenth",
11: "eleventh",
12: "twelfth",
13: "thirteenth",
14: "fourteenth",
15: "fifteenth",
16: "sixteenth",
17: "seventeenth",
18: "eighteenth",
19: "nineteenth",
20: "twentieth",
}
func genParamKey(argIdx int) string {
return "arg" + posWords[argIdx] // argfirst, argsecond...
return "param" + strconv.Itoa(argIdx) // param0, param1, param2...
}
type methodParser struct {
lexer *methodLexer
fn reflect.Method
lexer *methodLexer
fn reflect.Method
macros macro.Macros
}
func parseMethod(fn reflect.Method, skipper func(string) bool) (method, path string, err error) {
func parseMethod(macros macro.Macros, fn reflect.Method, skipper func(string) bool) (method, path string, err error) {
if skipper(fn.Name) {
return "", "", errSkip
}
p := &methodParser{
fn: fn,
lexer: newMethodLexer(fn.Name),
fn: fn,
lexer: newMethodLexer(fn.Name),
macros: macros,
}
return p.parse()
}
@@ -211,34 +190,45 @@ func (p *methodParser) parsePathParam(path string, w string, funcArgPos int) (st
var (
paramKey = genParamKey(funcArgPos) // argfirst, argsecond...
paramType = ast.ParamTypeString // default string
m = p.macros.GetMaster() // default (String by-default)
trailings = p.macros.GetTrailings()
)
// string, int...
goType := typ.In(funcArgPos).Name()
goType := typ.In(funcArgPos).Kind()
nextWord := p.lexer.peekNext()
if nextWord == tokenWildcard {
p.lexer.skip() // skip the Wildcard word.
paramType = ast.ParamTypePath
} else if pType := ast.LookupParamTypeFromStd(goType); pType != ast.ParamTypeUnExpected {
// it's not wildcard, so check base on our available macro types.
paramType = pType
} else {
if typ.NumIn() > funcArgPos {
// has more input arguments but we are not in the correct
// index now, maybe the first argument was an `iris/context.Context`
// so retry with the "funcArgPos" incremented.
//
// the "funcArgPos" will be updated to the caller as well
// because we return it among the path and the error.
return p.parsePathParam(path, w, funcArgPos+1)
if len(trailings) == 0 {
return "", 0, errors.New("no trailing path parameter found")
}
m = trailings[0]
} else {
// validMacros := p.macros.LookupForGoType(goType)
// instead of mapping with a reflect.Kind which has its limitation,
// we map the param types with a go type as a string,
// so custom structs such as "user" can be mapped to a macro with indent || alias == "user".
m = p.macros.Get(strings.ToLower(goType.String()))
if m == nil {
if typ.NumIn() > funcArgPos {
// has more input arguments but we are not in the correct
// index now, maybe the first argument was an `iris/context.Context`
// so retry with the "funcArgPos" incremented.
//
// the "funcArgPos" will be updated to the caller as well
// because we return it among the path and the error.
return p.parsePathParam(path, w, funcArgPos+1)
}
return "", 0, fmt.Errorf("invalid syntax: the standard go type: %s found in controller's function: %s at position: %d does not match any valid macro", goType, p.fn.Name, funcArgPos)
}
return "", 0, errors.New("invalid syntax for " + p.fn.Name)
}
// /{argfirst:path}, /{argfirst:long}...
path += fmt.Sprintf("/{%s:%s}", paramKey, paramType.String())
path += fmt.Sprintf("/{%s:%s}", paramKey, m.Indent())
if nextWord == "" && typ.NumIn() > funcArgPos+1 {
// By is the latest word but func is expected

View File

@@ -365,7 +365,9 @@ func (c *testControllerRelPathFromFunc) EndRequest(ctx context.Context) {
}
func (c *testControllerRelPathFromFunc) Get() {}
func (c *testControllerRelPathFromFunc) GetBy(int64) {}
func (c *testControllerRelPathFromFunc) GetBy(uint64) {}
func (c *testControllerRelPathFromFunc) GetUint8RatioBy(uint8) {}
func (c *testControllerRelPathFromFunc) GetInt64RatioBy(int64) {}
func (c *testControllerRelPathFromFunc) GetAnythingByWildcard(string) {}
func (c *testControllerRelPathFromFunc) GetLogin() {}
@@ -375,8 +377,10 @@ func (c *testControllerRelPathFromFunc) GetAdminLogin() {}
func (c *testControllerRelPathFromFunc) PutSomethingIntoThis() {}
func (c *testControllerRelPathFromFunc) GetSomethingBy(bool) {}
func (c *testControllerRelPathFromFunc) GetSomethingByBy(string, int) {}
func (c *testControllerRelPathFromFunc) GetSomethingBy(bool) {}
func (c *testControllerRelPathFromFunc) GetSomethingByBy(string, int) {}
func (c *testControllerRelPathFromFunc) GetSomethingNewBy(string, int) {} // two input arguments, one By which is the latest word.
func (c *testControllerRelPathFromFunc) GetSomethingByElseThisBy(bool, int) {} // two input arguments
@@ -388,8 +392,13 @@ func TestControllerRelPathFromFunc(t *testing.T) {
e.GET("/").Expect().Status(iris.StatusOK).
Body().Equal("GET:/")
e.GET("/42").Expect().Status(iris.StatusOK).
Body().Equal("GET:/42")
e.GET("/18446744073709551615").Expect().Status(iris.StatusOK).
Body().Equal("GET:/18446744073709551615")
e.GET("/uint8/ratio/255").Expect().Status(iris.StatusOK).
Body().Equal("GET:/uint8/ratio/255")
e.GET("/uint8/ratio/256").Expect().Status(iris.StatusNotFound)
e.GET("/int64/ratio/-42").Expect().Status(iris.StatusOK).
Body().Equal("GET:/int64/ratio/-42")
e.GET("/something/true").Expect().Status(iris.StatusOK).
Body().Equal("GET:/something/true")
e.GET("/something/false").Expect().Status(iris.StatusOK).

View File

@@ -4,8 +4,7 @@ import (
"reflect"
"github.com/kataras/iris/context"
"github.com/kataras/iris/core/router/macro"
"github.com/kataras/iris/core/router/macro/interpreter/ast"
"github.com/kataras/iris/macro"
)
func getPathParamsForInput(params []macro.TemplateParam, funcIn ...reflect.Type) (values []reflect.Value) {
@@ -13,51 +12,40 @@ func getPathParamsForInput(params []macro.TemplateParam, funcIn ...reflect.Type)
return
}
consumedParams := make(map[int]bool, 0)
for _, in := range funcIn {
for j, p := range params {
if _, consumed := consumedParams[j]; consumed {
continue
}
paramType := p.Type
paramName := p.Name
// fmt.Printf("%s input arg type vs %s param type\n", in.Kind().String(), p.Type.Kind().String())
if paramType.Assignable(in.Kind()) {
consumedParams[j] = true
// fmt.Printf("param.go: bind path param func for paramName = '%s' and paramType = '%s'\n", paramName, paramType.String())
values = append(values, makeFuncParamGetter(paramType, paramName))
}
// consumedParams := make(map[int]bool, 0)
// for _, in := range funcIn {
// for j, p := range params {
// if _, consumed := consumedParams[j]; consumed {
// continue
// }
// // fmt.Printf("%s input arg type vs %s param type\n", in.Kind().String(), p.Type.Kind().String())
// if m := macros.Lookup(p.Type); m != nil && m.GoType == in.Kind() {
// consumedParams[j] = true
// // fmt.Printf("param.go: bind path param func for paramName = '%s' and paramType = '%s'\n", paramName, paramType.String())
// funcDep, ok := context.ParamResolverByKindAndIndex(m.GoType, p.Index)
// // funcDep, ok := context.ParamResolverByKindAndKey(in.Kind(), paramName)
// if !ok {
// // here we can add a logger about invalid parameter type although it should never happen here
// // unless the end-developer modified the macro/macros with a special type but not the context/ParamResolvers.
// continue
// }
// values = append(values, funcDep)
// }
// }
// }
for i, param := range params {
if len(funcIn) <= i {
return
}
funcDep, ok := context.ParamResolverByTypeAndIndex(funcIn[i], param.Index)
if !ok {
continue
}
values = append(values, funcDep)
}
return
}
func makeFuncParamGetter(paramType ast.ParamType, paramName string) reflect.Value {
var fn interface{}
switch paramType {
case ast.ParamTypeInt:
fn = func(ctx context.Context) int {
v, _ := ctx.Params().GetInt(paramName)
return v
}
case ast.ParamTypeLong:
fn = func(ctx context.Context) int64 {
v, _ := ctx.Params().GetInt64(paramName)
return v
}
case ast.ParamTypeBoolean:
fn = func(ctx context.Context) bool {
v, _ := ctx.Params().GetBool(paramName)
return v
}
default:
// string, path...
fn = func(ctx context.Context) string {
return ctx.Params().Get(paramName)
}
}
return reflect.ValueOf(fn)
}