phase #1
This commit is contained in:
		
							parent
							
								
									405c170d45
								
							
						
					
					
						commit
						9aedb4d05a
					
				| @ -28,6 +28,7 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	"github.com/astaxie/beego/context" | 	"github.com/astaxie/beego/context" | ||||||
|  | 	"github.com/astaxie/beego/param" | ||||||
| 	"github.com/astaxie/beego/session" | 	"github.com/astaxie/beego/session" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -51,6 +52,7 @@ type ControllerComments struct { | |||||||
| 	Router           string | 	Router           string | ||||||
| 	AllowHTTPMethods []string | 	AllowHTTPMethods []string | ||||||
| 	Params           []map[string]string | 	Params           []map[string]string | ||||||
|  | 	MethodParams     []*param.MethodParam | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Controller defines some basic http request handler operations, such as | // Controller defines some basic http request handler operations, such as | ||||||
|  | |||||||
							
								
								
									
										101
									
								
								param/methodparams.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								param/methodparams.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | |||||||
|  | package param | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 
 | ||||||
|  | 	beecontext "github.com/astaxie/beego/context" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | //Keeps param information to be auto passed to controller methods | ||||||
|  | type MethodParam struct { | ||||||
|  | 	name     string | ||||||
|  | 	parser   paramParser | ||||||
|  | 	location paramLocation | ||||||
|  | 	required bool | ||||||
|  | 	defValue interface{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type paramLocation byte | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	param paramLocation = iota | ||||||
|  | 	body | ||||||
|  | 	header | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type MethodParamOption func(*MethodParam) | ||||||
|  | 
 | ||||||
|  | func Bool(name string, opts ...MethodParamOption) *MethodParam { | ||||||
|  | 	return newParam(name, boolParser{}, opts) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func String(name string, opts ...MethodParamOption) *MethodParam { | ||||||
|  | 	return newParam(name, stringParser{}, opts) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func Int(name string, opts ...MethodParamOption) *MethodParam { | ||||||
|  | 	return newParam(name, intParser{}, opts) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) { | ||||||
|  | 	param = &MethodParam{name: name, parser: parser} | ||||||
|  | 	for _, option := range opts { | ||||||
|  | 		option(param) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { | ||||||
|  | 	result = make([]reflect.Value, 0, len(methodParams)) | ||||||
|  | 	i := 0 | ||||||
|  | 	for _, p := range methodParams { | ||||||
|  | 		var strValue string | ||||||
|  | 		var value interface{} | ||||||
|  | 		switch p.location { | ||||||
|  | 		case body: | ||||||
|  | 			strValue = string(ctx.Input.RequestBody) | ||||||
|  | 		case header: | ||||||
|  | 			strValue = ctx.Input.Header(p.name) | ||||||
|  | 		default: | ||||||
|  | 			strValue = ctx.Input.Query(p.name) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if strValue == "" { | ||||||
|  | 			if p.required { | ||||||
|  | 				ctx.Abort(400, "Missing argument "+p.name) | ||||||
|  | 			} else if p.defValue != nil { | ||||||
|  | 				value = p.defValue | ||||||
|  | 			} else { | ||||||
|  | 				value = p.parser.zeroValue() | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			var err error | ||||||
|  | 			value, err = p.parser.parse(strValue) | ||||||
|  | 			if err != nil { | ||||||
|  | 				//TODO: handle err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		reflectValue, err := safeConvert(reflect.ValueOf(value), methodType.In(i)) | ||||||
|  | 		if err != nil { | ||||||
|  | 			//TODO: handle err | ||||||
|  | 		} | ||||||
|  | 		result = append(result, reflectValue) | ||||||
|  | 		i++ | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) { | ||||||
|  | 	defer func() { | ||||||
|  | 		if r := recover(); r != nil { | ||||||
|  | 			var ok bool | ||||||
|  | 			err, ok = r.(error) | ||||||
|  | 			if !ok { | ||||||
|  | 				err = fmt.Errorf("%v", r) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  | 	result = value.Convert(t) | ||||||
|  | 	return | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								param/options.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								param/options.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | package param | ||||||
|  | 
 | ||||||
|  | var InHeader MethodParamOption = func(p *MethodParam) { | ||||||
|  | 	p.location = header | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var IsRequired MethodParamOption = func(p *MethodParam) { | ||||||
|  | 	p.required = true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func Default(defValue interface{}) MethodParamOption { | ||||||
|  | 	return func(p *MethodParam) { | ||||||
|  | 		p.defValue = defValue | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								param/parsers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								param/parsers.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | package param | ||||||
|  | 
 | ||||||
|  | import "strconv" | ||||||
|  | 
 | ||||||
|  | type paramParser interface { | ||||||
|  | 	parse(value string) (interface{}, error) | ||||||
|  | 	zeroValue() interface{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type boolParser struct { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p boolParser) parse(value string) (interface{}, error) { | ||||||
|  | 	return strconv.ParseBool(value) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p boolParser) zeroValue() interface{} { | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type stringParser struct { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p stringParser) parse(value string) (interface{}, error) { | ||||||
|  | 	return value, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p stringParser) zeroValue() interface{} { | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type intParser struct { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p intParser) parse(value string) (interface{}, error) { | ||||||
|  | 	return strconv.Atoi(value) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p intParser) zeroValue() interface{} { | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								response/renderer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								response/renderer.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | package response | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"strconv" | ||||||
|  | 
 | ||||||
|  | 	beecontext "github.com/astaxie/beego/context" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type Renderer interface { | ||||||
|  | 	Render(ctx *beecontext.Context) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type rendererFunc func(ctx *beecontext.Context) | ||||||
|  | 
 | ||||||
|  | func (f rendererFunc) Render(ctx *beecontext.Context) { | ||||||
|  | 	f(ctx) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type StatusCode int | ||||||
|  | 
 | ||||||
|  | func (s StatusCode) Error() string { | ||||||
|  | 	return strconv.Itoa(int(s)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s StatusCode) Render(ctx *beecontext.Context) { | ||||||
|  | 	ctx.Output.SetStatus(int(s)) | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								response/responses.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								response/responses.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | package response | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	beecontext "github.com/astaxie/beego/context" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func Json(value interface{}, encoding ...bool) Renderer { | ||||||
|  | 	return rendererFunc(func(ctx *beecontext.Context) { | ||||||
|  | 		var ( | ||||||
|  | 			hasIndent   = true | ||||||
|  | 			hasEncoding = false | ||||||
|  | 		) | ||||||
|  | 		//TODO: need access to BConfig :( | ||||||
|  | 		// if BConfig.RunMode == PROD { | ||||||
|  | 		// 	hasIndent = false | ||||||
|  | 		// } | ||||||
|  | 		if len(encoding) > 0 && encoding[0] { | ||||||
|  | 			hasEncoding = true | ||||||
|  | 		} | ||||||
|  | 		ctx.Output.JSON(value, hasIndent, hasEncoding) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func Error(err error) Renderer { | ||||||
|  | 	return rendererFunc(func(ctx *beecontext.Context) { | ||||||
|  | 		ctx.Output.SetStatus(500) | ||||||
|  | 		ctx.WriteString(err.Error()) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func RenderMethodResult(result interface{}, ctx *beecontext.Context) { | ||||||
|  | 	if result != nil { | ||||||
|  | 		renderer, ok := result.(Renderer) | ||||||
|  | 		if !ok { | ||||||
|  | 			err, ok := result.(error) | ||||||
|  | 			if ok { | ||||||
|  | 				renderer = Error(err) | ||||||
|  | 			} else { | ||||||
|  | 				renderer = Json(result) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		renderer.Render(ctx) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								router.go
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								router.go
									
									
									
									
									
								
							| @ -29,6 +29,8 @@ import ( | |||||||
| 
 | 
 | ||||||
| 	beecontext "github.com/astaxie/beego/context" | 	beecontext "github.com/astaxie/beego/context" | ||||||
| 	"github.com/astaxie/beego/logs" | 	"github.com/astaxie/beego/logs" | ||||||
|  | 	"github.com/astaxie/beego/param" | ||||||
|  | 	"github.com/astaxie/beego/response" | ||||||
| 	"github.com/astaxie/beego/toolbox" | 	"github.com/astaxie/beego/toolbox" | ||||||
| 	"github.com/astaxie/beego/utils" | 	"github.com/astaxie/beego/utils" | ||||||
| ) | ) | ||||||
| @ -116,6 +118,7 @@ type controllerInfo struct { | |||||||
| 	handler        http.Handler | 	handler        http.Handler | ||||||
| 	runFunction    FilterFunc | 	runFunction    FilterFunc | ||||||
| 	routerType     int | 	routerType     int | ||||||
|  | 	methodParams   []*param.MethodParam | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ControllerRegister containers registered router rules, controller handlers and filters. | // ControllerRegister containers registered router rules, controller handlers and filters. | ||||||
| @ -151,6 +154,10 @@ func NewControllerRegister() *ControllerRegister { | |||||||
| //	Add("/api",&RestController{},"get,post:ApiFunc" | //	Add("/api",&RestController{},"get,post:ApiFunc" | ||||||
| //	Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc") | //	Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc") | ||||||
| func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) { | func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) { | ||||||
|  | 	p.addWithMethodParams(pattern, c, nil, mappingMethods...) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, mappingMethods ...string) { | ||||||
| 	reflectVal := reflect.ValueOf(c) | 	reflectVal := reflect.ValueOf(c) | ||||||
| 	t := reflect.Indirect(reflectVal).Type() | 	t := reflect.Indirect(reflectVal).Type() | ||||||
| 	methods := make(map[string]string) | 	methods := make(map[string]string) | ||||||
| @ -181,6 +188,7 @@ func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingM | |||||||
| 	route.methods = methods | 	route.methods = methods | ||||||
| 	route.routerType = routerTypeBeego | 	route.routerType = routerTypeBeego | ||||||
| 	route.controllerType = t | 	route.controllerType = t | ||||||
|  | 	route.methodParams = methodParams | ||||||
| 	if len(methods) == 0 { | 	if len(methods) == 0 { | ||||||
| 		for _, m := range HTTPMETHOD { | 		for _, m := range HTTPMETHOD { | ||||||
| 			p.addToRouter(m, pattern, route) | 			p.addToRouter(m, pattern, route) | ||||||
| @ -247,7 +255,7 @@ func (p *ControllerRegister) Include(cList ...ControllerInterface) { | |||||||
| 		key := t.PkgPath() + ":" + t.Name() | 		key := t.PkgPath() + ":" + t.Name() | ||||||
| 		if comm, ok := GlobalControllerRouter[key]; ok { | 		if comm, ok := GlobalControllerRouter[key]; ok { | ||||||
| 			for _, a := range comm { | 			for _, a := range comm { | ||||||
| 				p.Add(a.Router, c, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method) | 				p.addWithMethodParams(a.Router, c, a.MethodParams, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -626,11 +634,12 @@ func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath str | |||||||
| func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) { | func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) { | ||||||
| 	startTime := time.Now() | 	startTime := time.Now() | ||||||
| 	var ( | 	var ( | ||||||
| 		runRouter  reflect.Type | 		runRouter    reflect.Type | ||||||
| 		findRouter bool | 		findRouter   bool | ||||||
| 		runMethod  string | 		runMethod    string | ||||||
| 		routerInfo *controllerInfo | 		methodParams []*param.MethodParam | ||||||
| 		isRunnable bool | 		routerInfo   *controllerInfo | ||||||
|  | 		isRunnable   bool | ||||||
| 	) | 	) | ||||||
| 	context := p.pool.Get().(*beecontext.Context) | 	context := p.pool.Get().(*beecontext.Context) | ||||||
| 	context.Reset(rw, r) | 	context.Reset(rw, r) | ||||||
| @ -742,6 +751,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) | |||||||
| 			routerInfo.handler.ServeHTTP(rw, r) | 			routerInfo.handler.ServeHTTP(rw, r) | ||||||
| 		} else { | 		} else { | ||||||
| 			runRouter = routerInfo.controllerType | 			runRouter = routerInfo.controllerType | ||||||
|  | 			methodParams = routerInfo.methodParams | ||||||
| 			method := r.Method | 			method := r.Method | ||||||
| 			if r.Method == "POST" && context.Input.Query("_method") == "PUT" { | 			if r.Method == "POST" && context.Input.Query("_method") == "PUT" { | ||||||
| 				method = "PUT" | 				method = "PUT" | ||||||
| @ -804,9 +814,14 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) | |||||||
| 				execController.Options() | 				execController.Options() | ||||||
| 			default: | 			default: | ||||||
| 				if !execController.HandlerFunc(runMethod) { | 				if !execController.HandlerFunc(runMethod) { | ||||||
| 					var in []reflect.Value |  | ||||||
| 					method := vc.MethodByName(runMethod) | 					method := vc.MethodByName(runMethod) | ||||||
| 					method.Call(in) | 					var in []reflect.Value = param.ConvertParams(methodParams, method.Type(), context) | ||||||
|  | 					out := method.Call(in) | ||||||
|  | 
 | ||||||
|  | 					//For backward compatibility we only handle response if we had incoming methodParams | ||||||
|  | 					if methodParams != nil { | ||||||
|  | 						p.handleParamResponse(context, execController, out) | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| @ -886,6 +901,17 @@ Admin: | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (p *ControllerRegister) handleParamResponse(context *beecontext.Context, execController ControllerInterface, results []reflect.Value) { | ||||||
|  | 	//looping in reverse order for the case when both error and value are returned and error sets the response status code | ||||||
|  | 	for i := len(results) - 1; i >= 0; i-- { | ||||||
|  | 		result := results[i] | ||||||
|  | 		if !result.IsNil() { | ||||||
|  | 			resultValue := result.Interface() | ||||||
|  | 			response.RenderMethodResult(resultValue, context) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // FindRouter Find Router info for URL | // FindRouter Find Router info for URL | ||||||
| func (p *ControllerRegister) FindRouter(context *beecontext.Context) (routerInfo *controllerInfo, isFind bool) { | func (p *ControllerRegister) FindRouter(context *beecontext.Context) (routerInfo *controllerInfo, isFind bool) { | ||||||
| 	var urlPath = context.Input.URL() | 	var urlPath = context.Input.URL() | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user