Skip to content
Browse files

Use a Plugin to run Interceptors

  • Loading branch information...
1 parent 7f2db3c commit f7f405accc8e31a48e5c4fd16da33f44e4f2fc8a @robfig committed Nov 23, 2012
Showing with 58 additions and 40 deletions.
  1. +16 −40 controller.go
  2. +41 −0 intercept.go
  3. +1 −0 mvc.go
View
56 controller.go
@@ -13,14 +13,16 @@ import (
)
type Controller struct {
- Name string
- Type *ControllerType
- MethodType *MethodType
+ Name string // The controller name, e.g. "Application"
+ Type *ControllerType // A description of the controller type.
+ MethodType *MethodType // A description of the invoked action type.
+ AppController interface{} // The controller that was instantiated.
Request *Request
Response *Response
+ Result Result
- Flash Flash // User cookie, cleared after each request.
+ Flash Flash // User cookie, cleared after 1 request.
Session Session // Session, stored in cookie, signed.
Params *Params // Parameters from URL and form (including multipart).
Args map[string]interface{} // Per-request scratch space.
@@ -84,41 +86,29 @@ func (c *Controller) Invoke(appControllerPtr reflect.Value, method reflect.Value
// Run the plugins.
plugins.BeforeRequest(c)
+ if c.Result != nil {
+ c.Result.Apply(c.Request, c.Response)
+ return
+ }
- // Calculate the Result by running the interceptors and the action.
- resultValue := func() reflect.Value {
- // Call the BEFORE interceptors
- result := c.invokeInterceptors(BEFORE, appControllerPtr)
- if result != nil {
- return reflect.ValueOf(result)
- }
-
- // Invoke the action.
- resultValue := method.Call(methodArgs)[0]
-
- // Call the AFTER interceptors
- result = c.invokeInterceptors(AFTER, appControllerPtr)
- if result != nil {
- return reflect.ValueOf(result)
- }
- return resultValue
- }()
+ // Invoke the action.
+ resultValue := method.Call(methodArgs)[0]
+ c.Result = resultValue.Interface().(Result)
plugins.AfterRequest(c)
- if resultValue.Kind() == reflect.Interface && resultValue.IsNil() {
+ // if resultValue.Kind() == reflect.Interface && resultValue.IsNil() {
+ if c.Result == nil {
return
}
- result := resultValue.Interface().(Result)
// Apply the result, which generally results in the ResponseWriter getting written.
- result.Apply(c.Request, c.Response)
+ c.Result.Apply(c.Request, c.Response)
}
// This function handles a panic in an action invocation.
// It cleans up the stack trace, logs it, and displays an error page.
func handleInvocationPanic(c *Controller, err interface{}) {
- c.invokeInterceptors(PANIC, reflect.ValueOf(c))
plugins.OnException(c, err)
stack := string(debug.Stack())
ERROR.Println(err, "\n", stack)
@@ -133,20 +123,6 @@ func handleInvocationPanic(c *Controller, err interface{}) {
c.RenderError(error).Apply(c.Request, c.Response)
}
-func (c *Controller) invokeInterceptors(when InterceptTime, appControllerPtr reflect.Value) Result {
- var result Result
- for _, intc := range getInterceptors(when, appControllerPtr) {
- resultValue := intc.Invoke(appControllerPtr)
- if !resultValue.IsNil() {
- result = resultValue.Interface().(Result)
- }
- if when == BEFORE && result != nil {
- return result
- }
- }
- return result
-}
-
func (c *Controller) RenderError(err error) Result {
return ErrorResult{c.RenderArgs, err}
}
View
41 intercept.go
@@ -84,6 +84,47 @@ func (i Interception) Invoke(val reflect.Value) reflect.Value {
return vals[0]
}
+type InterceptorPlugin struct {
+ EmptyPlugin
+}
+
+func (p InterceptorPlugin) BeforeRequest(c *Controller) {
+ invokeInterceptors(BEFORE, c)
+}
+
+func (p InterceptorPlugin) AfterRequest(c *Controller) {
+ invokeInterceptors(AFTER, c)
+}
+
+func (p InterceptorPlugin) OnException(c *Controller, err interface{}) {
+ invokeInterceptors(PANIC, c)
+}
+
+func init() {
+ RegisterPlugin(InterceptorPlugin{})
+}
+
+func invokeInterceptors(when InterceptTime, c *Controller) {
+ appControllerPtr := reflect.ValueOf(c.AppController)
+ result := func() Result {
+ var result Result
+ for _, intc := range getInterceptors(when, appControllerPtr) {
+ resultValue := intc.Invoke(appControllerPtr)
+ if !resultValue.IsNil() {
+ result = resultValue.Interface().(Result)
+ }
+ if when == BEFORE && result != nil {
+ return result
+ }
+ }
+ return result
+ }()
+
+ if result != nil {
+ appControllerPtr.FieldByName("Result").Set(reflect.ValueOf(result))
+ }
+}
+
var interceptors []*Interception
// Install a general interceptor.
View
1 mvc.go
@@ -47,6 +47,7 @@ func NewAppController(req *Request, resp *Response, controllerName, methodName s
appControllerPtr := initNewAppController(appControllerType.Type, controller)
// Set the method being called.
+ controller.AppController = appControllerPtr.Interface()
controller.MethodType = appControllerType.Method(methodName)
if controller.MethodType == nil {
INFO.Println("Failed to find method", methodName, "on Controller",

0 comments on commit f7f405a

Please sign in to comment.
Something went wrong with that request. Please try again.