123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- package hero
- import (
- "fmt"
- "reflect"
- "github.com/kataras/iris/context"
- )
- type (
- // ErrorHandler describes an interface to handle errors per hero handler and its dependencies.
- //
- // Handles non-nil errors return from a hero handler or a controller's method (see `getBindingsFor` and `Handler`)
- // the error may return from a request-scoped dependency too (see `Handler`).
- ErrorHandler interface {
- HandleError(*context.Context, error)
- }
- // ErrorHandlerFunc implements the `ErrorHandler`.
- // It describes the type defnition for an error function handler.
- ErrorHandlerFunc func(*context.Context, error)
- )
- // HandleError fires when a non-nil error returns from a request-scoped dependency at serve-time or the handler itself.
- func (fn ErrorHandlerFunc) HandleError(ctx *context.Context, err error) {
- fn(ctx, err)
- }
- var (
- // ErrSeeOther may be returned from a dependency handler to skip a specific dependency
- // based on custom logic.
- ErrSeeOther = fmt.Errorf("see other")
- // ErrStopExecution may be returned from a dependency handler to stop
- // and return the execution of the function without error (it calls ctx.StopExecution() too).
- // It may be occurred from request-scoped dependencies as well.
- ErrStopExecution = fmt.Errorf("stop execution")
- )
- var (
- // DefaultErrStatusCode is the default error status code (400)
- // when the response contains a non-nil error or a request-scoped binding error occur.
- DefaultErrStatusCode = 400
- // DefaultErrorHandler is the default error handler which is fired
- // when a function returns a non-nil error or a request-scoped dependency failed to binded.
- DefaultErrorHandler = ErrorHandlerFunc(func(ctx *context.Context, err error) {
- if err != ErrStopExecution {
- if status := ctx.GetStatusCode(); status == 0 || !context.StatusCodeNotSuccessful(status) {
- ctx.StatusCode(DefaultErrStatusCode)
- }
- _, _ = ctx.WriteString(err.Error())
- }
- ctx.StopExecution()
- })
- )
- func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler {
- if fn == nil {
- panic("makeHandler: function is nil")
- }
- // 0. A normal handler.
- if handler, ok := isHandler(fn); ok {
- return handler
- }
- // 1. A handler which returns just an error, handle it faster.
- if handlerWithErr, ok := isHandlerWithError(fn); ok {
- return func(ctx *context.Context) {
- if err := handlerWithErr(ctx); err != nil {
- c.GetErrorHandler(ctx).HandleError(ctx, err)
- }
- }
- }
- v := valueOf(fn)
- typ := v.Type()
- numIn := typ.NumIn()
- bindings := getBindingsForFunc(v, c.Dependencies, paramsCount)
- resultHandler := defaultResultHandler
- for i, lidx := 0, len(c.resultHandlers)-1; i <= lidx; i++ {
- resultHandler = c.resultHandlers[lidx-i](resultHandler)
- }
- return func(ctx *context.Context) {
- inputs := make([]reflect.Value, numIn)
- for _, binding := range bindings {
- input, err := binding.Dependency.Handle(ctx, binding.Input)
- if err != nil {
- if err == ErrSeeOther {
- continue
- }
- // handled inside ErrorHandler.
- // else if err == ErrStopExecution {
- // ctx.StopExecution()
- // return // return without error.
- // }
- c.GetErrorHandler(ctx).HandleError(ctx, err)
- return
- }
- // If ~an error status code is set or~ execution has stopped
- // from within the dependency (something went wrong while validating the request),
- // then stop everything and let handler fire that status code.
- if ctx.IsStopped() /* || context.StatusCodeNotSuccessful(ctx.GetStatusCode())*/ {
- return
- }
- inputs[binding.Input.Index] = input
- }
- // fmt.Printf("For func: %s | valid input deps length(%d)\n", typ.String(), len(inputs))
- // for idx, in := range inputs {
- // fmt.Printf("[%d] (%s) %#+v\n", idx, in.Type().String(), in.Interface())
- // }
- outputs := v.Call(inputs)
- if err := dispatchFuncResult(ctx, outputs, resultHandler); err != nil {
- c.GetErrorHandler(ctx).HandleError(ctx, err)
- }
- }
- }
- func isHandler(fn interface{}) (context.Handler, bool) {
- if handler, ok := fn.(context.Handler); ok {
- return handler, ok
- }
- if handler, ok := fn.(func(*context.Context)); ok {
- return handler, ok
- }
- return nil, false
- }
- func isHandlerWithError(fn interface{}) (func(*context.Context) error, bool) {
- if handlerWithErr, ok := fn.(func(*context.Context) error); ok {
- return handlerWithErr, true
- }
- return nil, false
- }
|