gf/net/ghttp/ghttp_server_router_hook.go

121 lines
3.1 KiB
Go
Raw Normal View History

2021-01-17 21:46:25 +08:00
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package ghttp
import (
2021-09-27 21:27:24 +08:00
"context"
"net/http"
"reflect"
2021-11-13 23:23:55 +08:00
"github.com/gogf/gf/v2/debug/gdebug"
)
2020-05-07 23:05:33 +08:00
// BindHookHandler registers handler for specified hook.
2019-06-19 09:06:52 +08:00
func (s *Server) BindHookHandler(pattern string, hook string, handler HandlerFunc) {
2021-11-07 21:31:33 +08:00
s.doBindHookHandler(context.TODO(), doBindHookHandlerInput{
Prefix: "",
Pattern: pattern,
HookName: hook,
Handler: handler,
Source: "",
})
}
2022-03-19 17:58:21 +08:00
// doBindHookHandlerInput is the input for BindHookHandler.
2021-11-07 21:31:33 +08:00
type doBindHookHandlerInput struct {
Prefix string
Pattern string
HookName string
Handler HandlerFunc
Source string
}
2022-03-19 17:58:21 +08:00
// doBindHookHandler is the internal handler for BindHookHandler.
2021-11-07 21:31:33 +08:00
func (s *Server) doBindHookHandler(ctx context.Context, in doBindHookHandlerInput) {
s.setHandler(
ctx,
setHandlerInput{
Prefix: in.Prefix,
Pattern: in.Pattern,
2022-05-06 20:25:21 +08:00
HandlerItem: &HandlerItem{
2021-11-07 21:31:33 +08:00
Type: HandlerTypeHook,
Name: gdebug.FuncPath(in.Handler),
Info: handlerFuncInfo{
Func: in.Handler,
Type: reflect.TypeOf(in.Handler),
},
HookName: in.HookName,
Source: in.Source,
},
},
2021-11-07 21:31:33 +08:00
)
}
2022-03-19 17:58:21 +08:00
// BindHookHandlerByMap registers handler for specified hook.
func (s *Server) BindHookHandlerByMap(pattern string, hookMap map[string]HandlerFunc) {
for k, v := range hookMap {
2019-06-19 09:06:52 +08:00
s.BindHookHandler(pattern, k, v)
}
}
2020-05-07 23:05:33 +08:00
// callHookHandler calls the hook handler by their registered sequences.
func (s *Server) callHookHandler(hook string, r *Request) {
if !r.hasHookHandler {
return
}
hookItems := r.getHookHandlers(hook)
2019-06-19 09:06:52 +08:00
if len(hookItems) > 0 {
2020-05-07 23:05:33 +08:00
// Backup the old router variable map.
oldRouterMap := r.routerMap
2019-06-19 09:06:52 +08:00
for _, item := range hookItems {
r.routerMap = item.Values
2020-05-07 23:05:33 +08:00
// DO NOT USE the router of the hook handler,
// which can overwrite the router of serving handler.
2019-06-19 09:06:52 +08:00
// r.Router = item.handler.router
if err := s.niceCallHookHandler(item.Handler.Info.Func, r); err != nil {
2019-06-19 09:06:52 +08:00
switch err {
2020-12-14 13:26:48 +08:00
case exceptionExit:
2019-06-19 09:06:52 +08:00
break
2020-12-14 13:26:48 +08:00
case exceptionExitAll:
2019-06-19 09:06:52 +08:00
fallthrough
2020-12-14 13:26:48 +08:00
case exceptionExitHook:
2019-06-19 09:06:52 +08:00
return
default:
r.Response.WriteStatus(http.StatusInternalServerError, err)
2019-06-19 09:06:52 +08:00
panic(err)
}
}
}
2020-05-07 23:05:33 +08:00
// Restore the old router variable map.
r.routerMap = oldRouterMap
2019-06-19 09:06:52 +08:00
}
}
2020-05-07 23:05:33 +08:00
// getHookHandlers retrieves and returns the hook handlers of specified hook.
2020-04-06 22:31:45 +08:00
func (r *Request) getHookHandlers(hook string) []*handlerParsedItem {
parsedItems := make([]*handlerParsedItem, 0, 4)
for _, v := range r.handlers {
if v.Handler.HookName != hook {
2020-04-06 22:31:45 +08:00
continue
}
item := v
parsedItems = append(parsedItems, item)
}
return parsedItems
}
2020-05-07 23:05:33 +08:00
// niceCallHookHandler nicely calls the hook handler function,
// which means it automatically catches and returns the possible panic error to
// avoid goroutine crash.
func (s *Server) niceCallHookHandler(f HandlerFunc, r *Request) (err interface{}) {
2019-06-19 09:06:52 +08:00
defer func() {
err = recover()
}()
f(r)
return
}