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 (
2019-06-19 09:06:52 +08:00
"bytes"
2019-12-04 10:03:03 +08:00
"github.com/gogf/gf/debug/gdebug"
2021-08-24 21:18:59 +08:00
"github.com/gogf/gf/errors/gcode"
2021-07-13 23:01:31 +08:00
"github.com/gogf/gf/errors/gerror"
"reflect"
2019-06-19 09:06:52 +08:00
"strings"
2019-07-29 21:01:19 +08:00
"github.com/gogf/gf/text/gstr"
2018-07-31 21:05:02 +08:00
)
2020-05-09 19:19:42 +08:00
// BindHandler registers a handler function to server with given pattern.
2021-07-13 23:01:31 +08:00
// The parameter `handler` can be type of:
// func(*ghttp.Request)
// func(context.Context)
// func(context.Context,TypeRequest)
// func(context.Context,TypeRequest) error
// func(context.Context,TypeRequest)(TypeResponse,error)
func ( s * Server ) BindHandler ( pattern string , handler interface { } ) {
funcInfo , err := s . checkAndCreateFuncInfo ( handler , "" , "" , "" )
if err != nil {
s . Logger ( ) . Error ( err . Error ( ) )
return
}
s . doBindHandler ( pattern , funcInfo , nil , "" )
2018-07-31 21:05:02 +08:00
}
2020-05-09 19:19:42 +08:00
// doBindHandler registers a handler function to server with given pattern.
// The parameter <pattern> is like:
// /user/list, put:/user, delete:/user, post:/user@goframe.org
2021-07-13 23:01:31 +08:00
func ( s * Server ) doBindHandler ( pattern string , funcInfo handlerFuncInfo , middleware [ ] HandlerFunc , source string ) {
2019-12-04 10:03:03 +08:00
s . setHandler ( pattern , & handlerItem {
2021-07-19 20:06:44 +08:00
Name : gdebug . FuncPath ( funcInfo . Func ) ,
Type : handlerTypeHandler ,
Info : funcInfo ,
Middleware : middleware ,
Source : source ,
2019-12-04 10:03:03 +08:00
} )
2018-07-31 21:05:02 +08:00
}
2020-05-09 19:19:42 +08:00
// bindHandlerByMap registers handlers to server using map.
2020-01-21 17:18:03 +08:00
func ( s * Server ) bindHandlerByMap ( m map [ string ] * handlerItem ) {
2019-06-19 09:06:52 +08:00
for p , h := range m {
2019-12-04 10:03:03 +08:00
s . setHandler ( p , h )
2019-06-19 09:06:52 +08:00
}
2018-07-31 21:05:02 +08:00
}
2020-05-09 19:19:42 +08:00
// mergeBuildInNameToPattern merges build-in names into the pattern according to the following
// rules, and the built-in names are named like "{.xxx}".
// Rule 1: The URI in pattern contains the {.struct} keyword, it then replaces the keyword with the struct name;
// Rule 2: The URI in pattern contains the {.method} keyword, it then replaces the keyword with the method name;
// Rule 2: If Rule 1 is not met, it then adds the method name directly to the URI in the pattern;
//
// The parameter <allowAppend> specifies whether allowing appending method name to the tail of pattern.
2018-08-16 21:33:47 +08:00
func ( s * Server ) mergeBuildInNameToPattern ( pattern string , structName , methodName string , allowAppend bool ) string {
2019-12-04 10:03:03 +08:00
structName = s . nameToUri ( structName )
methodName = s . nameToUri ( methodName )
2019-06-19 09:06:52 +08:00
pattern = strings . Replace ( pattern , "{.struct}" , structName , - 1 )
if strings . Index ( pattern , "{.method}" ) != - 1 {
return strings . Replace ( pattern , "{.method}" , methodName , - 1 )
}
if ! allowAppend {
return pattern
}
2020-05-09 19:19:42 +08:00
// Check domain parameter.
2019-06-19 09:06:52 +08:00
array := strings . Split ( pattern , "@" )
uri := array [ 0 ]
uri = strings . TrimRight ( uri , "/" ) + "/" + methodName
2020-05-09 19:19:42 +08:00
// Append the domain parameter to URI.
2019-06-19 09:06:52 +08:00
if len ( array ) > 1 {
return uri + "@" + array [ 1 ]
}
return uri
2018-07-31 21:05:02 +08:00
}
2020-05-09 19:19:42 +08:00
// nameToUri converts the given name to URL format using following rules:
// Rule 0: Convert all method names to lowercase, add char '-' between words.
// Rule 1: Do not convert the method name, construct the URI with the original method name.
// Rule 2: Convert all method names to lowercase, no connecting symbols between words.
// Rule 3: Use camel case naming.
2019-12-04 10:03:03 +08:00
func ( s * Server ) nameToUri ( name string ) string {
2019-06-19 09:06:52 +08:00
switch s . config . NameToUriType {
2021-07-13 23:01:31 +08:00
case UriTypeFullName :
2019-06-19 09:06:52 +08:00
return name
2018-08-12 12:36:02 +08:00
2021-07-13 23:01:31 +08:00
case UriTypeAllLower :
2019-06-19 09:06:52 +08:00
return strings . ToLower ( name )
2018-08-12 12:36:02 +08:00
2021-07-13 23:01:31 +08:00
case UriTypeCamel :
2019-06-19 09:06:52 +08:00
part := bytes . NewBuffer ( nil )
if gstr . IsLetterUpper ( name [ 0 ] ) {
part . WriteByte ( name [ 0 ] + 32 )
} else {
part . WriteByte ( name [ 0 ] )
}
part . WriteString ( name [ 1 : ] )
return part . String ( )
2018-08-12 12:36:02 +08:00
2021-07-13 23:01:31 +08:00
case UriTypeDefault :
2019-06-19 09:06:52 +08:00
fallthrough
2021-07-13 23:01:31 +08:00
2019-06-19 09:06:52 +08:00
default :
part := bytes . NewBuffer ( nil )
for i := 0 ; i < len ( name ) ; i ++ {
if i > 0 && gstr . IsLetterUpper ( name [ i ] ) {
part . WriteByte ( '-' )
}
if gstr . IsLetterUpper ( name [ i ] ) {
part . WriteByte ( name [ i ] + 32 )
} else {
part . WriteByte ( name [ i ] )
}
}
return part . String ( )
}
}
2021-07-13 23:01:31 +08:00
func ( s * Server ) checkAndCreateFuncInfo ( f interface { } , pkgPath , objName , methodName string ) ( info handlerFuncInfo , err error ) {
handlerFunc , ok := f . ( HandlerFunc )
if ! ok {
reflectType := reflect . TypeOf ( f )
if reflectType . NumIn ( ) == 0 || reflectType . NumIn ( ) > 2 || reflectType . NumOut ( ) > 2 {
if pkgPath != "" {
2021-07-20 23:02:02 +08:00
err = gerror . NewCodef (
2021-08-24 21:18:59 +08:00
gcode . CodeInvalidParameter ,
2021-07-13 23:01:31 +08:00
` invalid handler: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" or "func(context.Context)/func(context.Context,Request)/func(context.Context,Request) error/func(context.Context,Request)(Response,error)" is required ` ,
pkgPath , objName , methodName , reflect . TypeOf ( f ) . String ( ) ,
)
} else {
2021-07-20 23:02:02 +08:00
err = gerror . NewCodef (
2021-08-24 21:18:59 +08:00
gcode . CodeInvalidParameter ,
2021-07-13 23:01:31 +08:00
` invalid handler: defined as "%s", but "func(*ghttp.Request)" or "func(context.Context)/func(context.Context,Request)/func(context.Context,Request) error/func(context.Context,Request)(Response,error)" is required ` ,
reflect . TypeOf ( f ) . String ( ) ,
)
}
return
}
if reflectType . In ( 0 ) . String ( ) != "context.Context" {
2021-07-20 23:02:02 +08:00
err = gerror . NewCodef (
2021-08-24 21:18:59 +08:00
gcode . CodeInvalidParameter ,
2021-07-13 23:01:31 +08:00
` invalid handler: defined as "%s", but the first input parameter should be type of "context.Context" ` ,
reflect . TypeOf ( f ) . String ( ) ,
)
return
}
if reflectType . NumOut ( ) > 0 && reflectType . Out ( reflectType . NumOut ( ) - 1 ) . String ( ) != "error" {
2021-07-20 23:02:02 +08:00
err = gerror . NewCodef (
2021-08-24 21:18:59 +08:00
gcode . CodeInvalidParameter ,
2021-07-13 23:01:31 +08:00
` invalid handler: defined as "%s", but the last output parameter should be type of "error" ` ,
reflect . TypeOf ( f ) . String ( ) ,
)
return
}
}
info . Func = handlerFunc
info . Type = reflect . TypeOf ( f )
info . Value = reflect . ValueOf ( f )
return
}