2021-01-17 21:46:25 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2018-07-31 21:05:02 +08:00
|
|
|
//
|
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
2018-07-31 21:05:02 +08:00
|
|
|
|
|
|
|
package ghttp
|
|
|
|
|
|
|
|
import (
|
2021-09-27 21:27:24 +08:00
|
|
|
"context"
|
2019-06-19 09:06:52 +08:00
|
|
|
"fmt"
|
2019-06-25 23:03:29 +08:00
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/os/gfile"
|
|
|
|
"github.com/gogf/gf/v2/text/gregex"
|
|
|
|
"github.com/gogf/gf/v2/text/gstr"
|
2018-07-31 21:05:02 +08:00
|
|
|
)
|
|
|
|
|
2020-05-09 19:19:42 +08:00
|
|
|
// BindObject registers object to server routes with given pattern.
|
|
|
|
//
|
2021-10-21 18:22:47 +08:00
|
|
|
// The optional parameter `method` is used to specify the method to be registered, which
|
2021-09-27 21:27:24 +08:00
|
|
|
// supports multiple method names, multiple methods are separated by char ',', case-sensitive.
|
2019-12-04 10:03:03 +08:00
|
|
|
func (s *Server) BindObject(pattern string, object interface{}, method ...string) {
|
2021-09-27 21:27:24 +08:00
|
|
|
var (
|
|
|
|
bindMethod = ""
|
|
|
|
)
|
2019-12-04 10:03:03 +08:00
|
|
|
if len(method) > 0 {
|
|
|
|
bindMethod = method[0]
|
|
|
|
}
|
2021-11-07 21:31:33 +08:00
|
|
|
s.doBindObject(context.TODO(), doBindObjectInput{
|
|
|
|
Prefix: "",
|
|
|
|
Pattern: pattern,
|
|
|
|
Object: object,
|
|
|
|
Method: bindMethod,
|
|
|
|
Middleware: nil,
|
|
|
|
Source: "",
|
|
|
|
})
|
2019-12-04 10:03:03 +08:00
|
|
|
}
|
|
|
|
|
2020-05-09 19:19:42 +08:00
|
|
|
// BindObjectMethod registers specified method of object to server routes with given pattern.
|
|
|
|
//
|
2021-10-21 18:22:47 +08:00
|
|
|
// The optional parameter `method` is used to specify the method to be registered, which
|
2021-09-27 21:27:24 +08:00
|
|
|
// does not supports multiple method names but only one, case-sensitive.
|
2019-12-04 10:03:03 +08:00
|
|
|
func (s *Server) BindObjectMethod(pattern string, object interface{}, method string) {
|
2021-11-07 21:31:33 +08:00
|
|
|
s.doBindObjectMethod(context.TODO(), doBindObjectMethodInput{
|
|
|
|
Prefix: "",
|
|
|
|
Pattern: pattern,
|
|
|
|
Object: object,
|
|
|
|
Method: method,
|
|
|
|
Middleware: nil,
|
|
|
|
Source: "",
|
|
|
|
})
|
2019-12-04 10:03:03 +08:00
|
|
|
}
|
|
|
|
|
2021-09-28 19:04:36 +08:00
|
|
|
// BindObjectRest registers object in REST API styles to server with specified pattern.
|
2019-12-04 10:03:03 +08:00
|
|
|
func (s *Server) BindObjectRest(pattern string, object interface{}) {
|
2021-11-07 21:31:33 +08:00
|
|
|
s.doBindObjectRest(context.TODO(), doBindObjectInput{
|
|
|
|
Prefix: "",
|
|
|
|
Pattern: pattern,
|
|
|
|
Object: object,
|
|
|
|
Method: "",
|
|
|
|
Middleware: nil,
|
|
|
|
Source: "",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
type doBindObjectInput struct {
|
|
|
|
Prefix string
|
|
|
|
Pattern string
|
|
|
|
Object interface{}
|
|
|
|
Method string
|
|
|
|
Middleware []HandlerFunc
|
|
|
|
Source string
|
2019-12-04 10:03:03 +08:00
|
|
|
}
|
|
|
|
|
2021-11-07 21:31:33 +08:00
|
|
|
func (s *Server) doBindObject(ctx context.Context, in doBindObjectInput) {
|
2020-03-05 16:08:55 +08:00
|
|
|
// Convert input method to map for convenience and high performance searching purpose.
|
2022-02-24 22:07:27 +08:00
|
|
|
var methodMap map[string]bool
|
2021-11-07 21:31:33 +08:00
|
|
|
if len(in.Method) > 0 {
|
2019-12-04 10:03:03 +08:00
|
|
|
methodMap = make(map[string]bool)
|
2021-11-07 21:31:33 +08:00
|
|
|
for _, v := range strings.Split(in.Method, ",") {
|
2019-12-04 10:03:03 +08:00
|
|
|
methodMap[strings.TrimSpace(v)] = true
|
|
|
|
}
|
|
|
|
}
|
2021-03-01 20:49:09 +08:00
|
|
|
// If the `method` in `pattern` is `defaultMethod`,
|
|
|
|
// it removes for convenience for next statement control.
|
2021-11-07 21:31:33 +08:00
|
|
|
domain, method, path, err := s.parsePattern(in.Pattern)
|
2019-06-25 23:03:29 +08:00
|
|
|
if err != nil {
|
2021-10-06 12:12:59 +08:00
|
|
|
s.Logger().Fatalf(ctx, `%+v`, err)
|
2019-06-25 23:03:29 +08:00
|
|
|
return
|
|
|
|
}
|
2020-12-14 13:26:48 +08:00
|
|
|
if strings.EqualFold(method, defaultMethod) {
|
2021-11-07 21:31:33 +08:00
|
|
|
in.Pattern = s.serveHandlerKey("", path, domain)
|
2019-06-25 23:03:29 +08:00
|
|
|
}
|
2021-03-01 20:49:09 +08:00
|
|
|
var (
|
2021-11-07 21:31:33 +08:00
|
|
|
handlerMap = make(map[string]*handlerItem)
|
|
|
|
reflectValue = reflect.ValueOf(in.Object)
|
|
|
|
reflectType = reflectValue.Type()
|
|
|
|
initFunc func(*Request)
|
|
|
|
shutFunc func(*Request)
|
2021-03-01 20:49:09 +08:00
|
|
|
)
|
|
|
|
// If given `object` is not pointer, it then creates a temporary one,
|
2022-01-01 00:18:50 +08:00
|
|
|
// of which the value is `reflectValue`.
|
|
|
|
// It then can retrieve all the methods both of struct/*struct.
|
2021-11-07 21:31:33 +08:00
|
|
|
if reflectValue.Kind() == reflect.Struct {
|
|
|
|
newValue := reflect.New(reflectType)
|
|
|
|
newValue.Elem().Set(reflectValue)
|
|
|
|
reflectValue = newValue
|
|
|
|
reflectType = reflectValue.Type()
|
2021-03-01 20:49:09 +08:00
|
|
|
}
|
2021-11-07 21:31:33 +08:00
|
|
|
structName := reflectType.Elem().Name()
|
2022-02-24 22:07:27 +08:00
|
|
|
if reflectValue.MethodByName(specialMethodNameInit).IsValid() {
|
|
|
|
initFunc = reflectValue.MethodByName(specialMethodNameInit).Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2022-02-24 22:07:27 +08:00
|
|
|
if reflectValue.MethodByName(specialMethodNameShut).IsValid() {
|
|
|
|
shutFunc = reflectValue.MethodByName(specialMethodNameShut).Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-11-07 21:31:33 +08:00
|
|
|
pkgPath := reflectType.Elem().PkgPath()
|
2019-06-19 09:06:52 +08:00
|
|
|
pkgName := gfile.Basename(pkgPath)
|
2021-11-07 21:31:33 +08:00
|
|
|
for i := 0; i < reflectValue.NumMethod(); i++ {
|
|
|
|
methodName := reflectType.Method(i).Name
|
2019-12-18 19:37:07 +08:00
|
|
|
if methodMap != nil && !methodMap[methodName] {
|
2019-06-19 09:06:52 +08:00
|
|
|
continue
|
|
|
|
}
|
2022-02-24 22:07:27 +08:00
|
|
|
if methodName == specialMethodNameInit || methodName == specialMethodNameShut {
|
2019-06-19 09:06:52 +08:00
|
|
|
continue
|
|
|
|
}
|
2021-11-07 21:31:33 +08:00
|
|
|
objName := gstr.Replace(reflectType.String(), fmt.Sprintf(`%s.`, pkgName), "")
|
2019-06-19 09:06:52 +08:00
|
|
|
if objName[0] == '*' {
|
|
|
|
objName = fmt.Sprintf(`(%s)`, objName)
|
|
|
|
}
|
2021-07-13 23:01:31 +08:00
|
|
|
|
2021-11-07 21:31:33 +08:00
|
|
|
funcInfo, err := s.checkAndCreateFuncInfo(reflectValue.Method(i).Interface(), pkgPath, objName, methodName)
|
2021-07-13 23:01:31 +08:00
|
|
|
if err != nil {
|
2021-10-06 12:12:59 +08:00
|
|
|
s.Logger().Fatalf(ctx, `%+v`, err)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-07-13 23:01:31 +08:00
|
|
|
|
2021-11-07 21:31:33 +08:00
|
|
|
key := s.mergeBuildInNameToPattern(in.Pattern, structName, methodName, true)
|
|
|
|
handlerMap[key] = &handlerItem{
|
2021-07-19 20:06:44 +08:00
|
|
|
Name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
|
2021-10-06 14:22:58 +08:00
|
|
|
Type: HandlerTypeObject,
|
2021-07-19 20:06:44 +08:00
|
|
|
Info: funcInfo,
|
|
|
|
InitFunc: initFunc,
|
|
|
|
ShutFunc: shutFunc,
|
2021-11-07 21:31:33 +08:00
|
|
|
Middleware: in.Middleware,
|
|
|
|
Source: in.Source,
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2020-05-09 19:19:42 +08:00
|
|
|
// If there's "Index" method, then an additional route is automatically added
|
|
|
|
// to match the main URI, for example:
|
|
|
|
// If pattern is "/user", then "/user" and "/user/index" are both automatically
|
|
|
|
// registered.
|
|
|
|
//
|
|
|
|
// Note that if there's built-in variables in pattern, this route will not be added
|
|
|
|
// automatically.
|
2022-02-24 22:07:27 +08:00
|
|
|
var (
|
|
|
|
isIndexMethod = strings.EqualFold(methodName, specialMethodNameIndex)
|
|
|
|
hasBuildInVar = gregex.IsMatchString(`\{\.\w+\}`, in.Pattern)
|
|
|
|
hashTwoParams = funcInfo.Type.NumIn() == 2
|
|
|
|
)
|
|
|
|
if isIndexMethod && !hasBuildInVar && !hashTwoParams {
|
2019-08-30 20:29:12 +08:00
|
|
|
p := gstr.PosRI(key, "/index")
|
2019-06-19 09:06:52 +08:00
|
|
|
k := key[0:p] + key[p+6:]
|
|
|
|
if len(k) == 0 || k[0] == '@' {
|
|
|
|
k = "/" + k
|
|
|
|
}
|
2021-11-07 21:31:33 +08:00
|
|
|
handlerMap[k] = &handlerItem{
|
2021-07-19 20:06:44 +08:00
|
|
|
Name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
|
2021-10-06 14:22:58 +08:00
|
|
|
Type: HandlerTypeObject,
|
2021-07-19 20:06:44 +08:00
|
|
|
Info: funcInfo,
|
|
|
|
InitFunc: initFunc,
|
|
|
|
ShutFunc: shutFunc,
|
2021-11-07 21:31:33 +08:00
|
|
|
Middleware: in.Middleware,
|
|
|
|
Source: in.Source,
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-07 21:31:33 +08:00
|
|
|
s.bindHandlerByMap(ctx, in.Prefix, handlerMap)
|
|
|
|
}
|
|
|
|
|
|
|
|
type doBindObjectMethodInput struct {
|
|
|
|
Prefix string
|
|
|
|
Pattern string
|
|
|
|
Object interface{}
|
|
|
|
Method string
|
|
|
|
Middleware []HandlerFunc
|
|
|
|
Source string
|
2018-07-31 21:05:02 +08:00
|
|
|
}
|
|
|
|
|
2021-11-07 21:31:33 +08:00
|
|
|
func (s *Server) doBindObjectMethod(ctx context.Context, in doBindObjectMethodInput) {
|
2021-03-01 20:49:09 +08:00
|
|
|
var (
|
2021-11-07 21:31:33 +08:00
|
|
|
handlerMap = make(map[string]*handlerItem)
|
|
|
|
reflectValue = reflect.ValueOf(in.Object)
|
|
|
|
reflectType = reflectValue.Type()
|
|
|
|
initFunc func(*Request)
|
|
|
|
shutFunc func(*Request)
|
2021-03-01 20:49:09 +08:00
|
|
|
)
|
|
|
|
// If given `object` is not pointer, it then creates a temporary one,
|
|
|
|
// of which the value is `v`.
|
2021-11-07 21:31:33 +08:00
|
|
|
if reflectValue.Kind() == reflect.Struct {
|
|
|
|
newValue := reflect.New(reflectType)
|
|
|
|
newValue.Elem().Set(reflectValue)
|
|
|
|
reflectValue = newValue
|
|
|
|
reflectType = reflectValue.Type()
|
2021-03-01 20:49:09 +08:00
|
|
|
}
|
2021-10-06 12:12:59 +08:00
|
|
|
var (
|
2021-11-07 21:31:33 +08:00
|
|
|
structName = reflectType.Elem().Name()
|
|
|
|
methodName = strings.TrimSpace(in.Method)
|
|
|
|
methodValue = reflectValue.MethodByName(methodName)
|
2021-10-06 12:12:59 +08:00
|
|
|
)
|
2019-12-18 19:37:07 +08:00
|
|
|
if !methodValue.IsValid() {
|
2021-10-06 12:12:59 +08:00
|
|
|
s.Logger().Fatalf(ctx, "invalid method name: %s", methodName)
|
2019-06-19 09:06:52 +08:00
|
|
|
return
|
|
|
|
}
|
2022-02-24 22:07:27 +08:00
|
|
|
if reflectValue.MethodByName(specialMethodNameInit).IsValid() {
|
|
|
|
initFunc = reflectValue.MethodByName(specialMethodNameInit).Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2022-02-24 22:07:27 +08:00
|
|
|
if reflectValue.MethodByName(specialMethodNameShut).IsValid() {
|
|
|
|
shutFunc = reflectValue.MethodByName(specialMethodNameShut).Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-10-06 12:12:59 +08:00
|
|
|
var (
|
2021-11-07 21:31:33 +08:00
|
|
|
pkgPath = reflectType.Elem().PkgPath()
|
2021-10-06 12:12:59 +08:00
|
|
|
pkgName = gfile.Basename(pkgPath)
|
2021-11-07 21:31:33 +08:00
|
|
|
objName = gstr.Replace(reflectType.String(), fmt.Sprintf(`%s.`, pkgName), "")
|
2021-10-06 12:12:59 +08:00
|
|
|
)
|
2019-06-19 09:06:52 +08:00
|
|
|
if objName[0] == '*' {
|
|
|
|
objName = fmt.Sprintf(`(%s)`, objName)
|
|
|
|
}
|
2021-07-13 23:01:31 +08:00
|
|
|
|
|
|
|
funcInfo, err := s.checkAndCreateFuncInfo(methodValue.Interface(), pkgPath, objName, methodName)
|
|
|
|
if err != nil {
|
2021-10-06 12:12:59 +08:00
|
|
|
s.Logger().Fatalf(ctx, `%+v`, err)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-07-13 23:01:31 +08:00
|
|
|
|
2021-11-07 21:31:33 +08:00
|
|
|
key := s.mergeBuildInNameToPattern(in.Pattern, structName, methodName, false)
|
|
|
|
handlerMap[key] = &handlerItem{
|
2021-07-19 20:06:44 +08:00
|
|
|
Name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
|
2021-10-06 14:22:58 +08:00
|
|
|
Type: HandlerTypeObject,
|
2021-07-19 20:06:44 +08:00
|
|
|
Info: funcInfo,
|
|
|
|
InitFunc: initFunc,
|
|
|
|
ShutFunc: shutFunc,
|
2021-11-07 21:31:33 +08:00
|
|
|
Middleware: in.Middleware,
|
|
|
|
Source: in.Source,
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2018-08-16 21:33:47 +08:00
|
|
|
|
2021-11-07 21:31:33 +08:00
|
|
|
s.bindHandlerByMap(ctx, in.Prefix, handlerMap)
|
2018-07-31 21:05:02 +08:00
|
|
|
}
|
|
|
|
|
2021-11-07 21:31:33 +08:00
|
|
|
func (s *Server) doBindObjectRest(ctx context.Context, in doBindObjectInput) {
|
2021-03-01 20:49:09 +08:00
|
|
|
var (
|
2021-11-07 21:31:33 +08:00
|
|
|
handlerMap = make(map[string]*handlerItem)
|
|
|
|
reflectValue = reflect.ValueOf(in.Object)
|
|
|
|
reflectType = reflectValue.Type()
|
|
|
|
initFunc func(*Request)
|
|
|
|
shutFunc func(*Request)
|
2021-03-01 20:49:09 +08:00
|
|
|
)
|
|
|
|
// If given `object` is not pointer, it then creates a temporary one,
|
|
|
|
// of which the value is `v`.
|
2021-11-07 21:31:33 +08:00
|
|
|
if reflectValue.Kind() == reflect.Struct {
|
|
|
|
newValue := reflect.New(reflectType)
|
|
|
|
newValue.Elem().Set(reflectValue)
|
|
|
|
reflectValue = newValue
|
|
|
|
reflectType = reflectValue.Type()
|
2021-03-01 20:49:09 +08:00
|
|
|
}
|
2021-11-07 21:31:33 +08:00
|
|
|
structName := reflectType.Elem().Name()
|
2022-02-24 22:07:27 +08:00
|
|
|
if reflectValue.MethodByName(specialMethodNameInit).IsValid() {
|
|
|
|
initFunc = reflectValue.MethodByName(specialMethodNameInit).Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2022-02-24 22:07:27 +08:00
|
|
|
if reflectValue.MethodByName(specialMethodNameShut).IsValid() {
|
|
|
|
shutFunc = reflectValue.MethodByName(specialMethodNameShut).Interface().(func(*Request))
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-11-07 21:31:33 +08:00
|
|
|
pkgPath := reflectType.Elem().PkgPath()
|
|
|
|
for i := 0; i < reflectValue.NumMethod(); i++ {
|
|
|
|
methodName := reflectType.Method(i).Name
|
2019-12-18 19:37:07 +08:00
|
|
|
if _, ok := methodsMap[strings.ToUpper(methodName)]; !ok {
|
2019-06-19 09:06:52 +08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
pkgName := gfile.Basename(pkgPath)
|
2021-11-07 21:31:33 +08:00
|
|
|
objName := gstr.Replace(reflectType.String(), fmt.Sprintf(`%s.`, pkgName), "")
|
2019-06-19 09:06:52 +08:00
|
|
|
if objName[0] == '*' {
|
|
|
|
objName = fmt.Sprintf(`(%s)`, objName)
|
|
|
|
}
|
2021-07-13 23:01:31 +08:00
|
|
|
|
2021-11-07 21:31:33 +08:00
|
|
|
funcInfo, err := s.checkAndCreateFuncInfo(
|
|
|
|
reflectValue.Method(i).Interface(),
|
|
|
|
pkgPath,
|
|
|
|
objName,
|
|
|
|
methodName,
|
|
|
|
)
|
2021-07-13 23:01:31 +08:00
|
|
|
if err != nil {
|
2021-10-06 12:12:59 +08:00
|
|
|
s.Logger().Fatalf(ctx, `%+v`, err)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2021-07-13 23:01:31 +08:00
|
|
|
|
2021-11-07 21:31:33 +08:00
|
|
|
key := s.mergeBuildInNameToPattern(methodName+":"+in.Pattern, structName, methodName, false)
|
|
|
|
handlerMap[key] = &handlerItem{
|
2021-07-19 20:06:44 +08:00
|
|
|
Name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
|
2021-10-06 14:22:58 +08:00
|
|
|
Type: HandlerTypeObject,
|
2021-07-19 20:06:44 +08:00
|
|
|
Info: funcInfo,
|
|
|
|
InitFunc: initFunc,
|
|
|
|
ShutFunc: shutFunc,
|
2021-11-07 21:31:33 +08:00
|
|
|
Middleware: in.Middleware,
|
|
|
|
Source: in.Source,
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
}
|
2021-11-07 21:31:33 +08:00
|
|
|
s.bindHandlerByMap(ctx, in.Prefix, handlerMap)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|