goext/ginext/routes.go

219 lines
5.5 KiB
Go
Raw Permalink Normal View History

2023-07-18 14:40:10 +02:00
package ginext
import (
"github.com/gin-gonic/gin"
2023-07-24 17:23:38 +02:00
"gogs.mikescher.com/BlackForestBytes/goext/langext"
2023-07-24 18:50:14 +02:00
"gogs.mikescher.com/BlackForestBytes/goext/rext"
2023-07-18 14:40:10 +02:00
"net/http"
2023-07-25 11:16:11 +02:00
"path"
2023-07-24 18:22:36 +02:00
"reflect"
2023-07-24 18:50:14 +02:00
"regexp"
2023-07-24 18:22:36 +02:00
"runtime"
"strings"
2023-07-18 14:40:10 +02:00
)
2023-07-18 16:08:24 +02:00
var anyMethods = []string{
http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch,
http.MethodHead, http.MethodOptions, http.MethodDelete, http.MethodConnect,
http.MethodTrace,
}
2023-07-18 14:40:10 +02:00
type GinRoutesWrapper struct {
2023-07-24 17:23:38 +02:00
wrapper *GinWrapper
routes gin.IRouter
2023-07-25 11:16:11 +02:00
absPath string
2023-07-24 17:23:38 +02:00
defaultHandler []gin.HandlerFunc
2023-07-18 14:40:10 +02:00
}
type GinRouteBuilder struct {
routes *GinRoutesWrapper
2023-07-24 18:22:36 +02:00
method string
2023-07-18 14:40:10 +02:00
relPath string
2023-07-25 11:16:11 +02:00
absPath string
2023-07-18 14:40:10 +02:00
handlers []gin.HandlerFunc
}
func (w *GinWrapper) Routes() *GinRoutesWrapper {
2023-07-25 11:16:11 +02:00
return &GinRoutesWrapper{
wrapper: w,
routes: w.engine,
absPath: "",
defaultHandler: make([]gin.HandlerFunc, 0),
}
2023-07-18 14:40:10 +02:00
}
func (w *GinRoutesWrapper) Group(relativePath string) *GinRoutesWrapper {
2023-07-25 11:16:11 +02:00
return &GinRoutesWrapper{
wrapper: w.wrapper,
routes: w.routes.Group(relativePath),
defaultHandler: langext.ArrCopy(w.defaultHandler),
absPath: joinPaths(w.absPath, relativePath),
}
2023-07-24 17:23:38 +02:00
}
func (w *GinRoutesWrapper) Use(middleware ...gin.HandlerFunc) *GinRoutesWrapper {
defHandler := langext.ArrCopy(w.defaultHandler)
defHandler = append(defHandler, middleware...)
return &GinRoutesWrapper{wrapper: w.wrapper, routes: w.routes, defaultHandler: defHandler}
2023-07-18 14:40:10 +02:00
}
func (w *GinRoutesWrapper) GET(relativePath string) *GinRouteBuilder {
2023-07-25 11:16:11 +02:00
return w._route(http.MethodGet, relativePath)
2023-07-18 14:40:10 +02:00
}
func (w *GinRoutesWrapper) POST(relativePath string) *GinRouteBuilder {
2023-07-25 11:16:11 +02:00
return w._route(http.MethodPost, relativePath)
2023-07-18 14:40:10 +02:00
}
func (w *GinRoutesWrapper) DELETE(relativePath string) *GinRouteBuilder {
2023-07-25 11:16:11 +02:00
return w._route(http.MethodDelete, relativePath)
2023-07-18 14:40:10 +02:00
}
func (w *GinRoutesWrapper) PATCH(relativePath string) *GinRouteBuilder {
2023-07-25 11:16:11 +02:00
return w._route(http.MethodPatch, relativePath)
2023-07-18 14:40:10 +02:00
}
func (w *GinRoutesWrapper) PUT(relativePath string) *GinRouteBuilder {
2023-07-25 11:16:11 +02:00
return w._route(http.MethodPut, relativePath)
2023-07-18 14:40:10 +02:00
}
func (w *GinRoutesWrapper) OPTIONS(relativePath string) *GinRouteBuilder {
2023-07-25 11:16:11 +02:00
return w._route(http.MethodOptions, relativePath)
2023-07-18 14:40:10 +02:00
}
func (w *GinRoutesWrapper) HEAD(relativePath string) *GinRouteBuilder {
2023-07-25 11:16:11 +02:00
return w._route(http.MethodHead, relativePath)
2023-07-18 14:40:10 +02:00
}
func (w *GinRoutesWrapper) COUNT(relativePath string) *GinRouteBuilder {
2023-07-25 11:16:11 +02:00
return w._route("COUNT", relativePath)
2023-07-18 16:08:24 +02:00
}
func (w *GinRoutesWrapper) Any(relativePath string) *GinRouteBuilder {
2023-07-25 11:16:11 +02:00
return w._route("*", relativePath)
}
func (w *GinRoutesWrapper) _route(method string, relativePath string) *GinRouteBuilder {
return &GinRouteBuilder{
routes: w,
method: method,
relPath: relativePath,
absPath: joinPaths(w.absPath, relativePath),
handlers: langext.ArrCopy(w.defaultHandler),
}
2023-07-18 14:40:10 +02:00
}
2023-07-19 11:20:35 +02:00
func (w *GinRouteBuilder) Use(middleware ...gin.HandlerFunc) *GinRouteBuilder {
w.handlers = append(w.handlers, middleware...)
2023-07-18 14:40:10 +02:00
return w
}
2023-07-18 15:23:32 +02:00
func (w *GinRouteBuilder) WithJSONFilter(filter string) *GinRouteBuilder {
w.handlers = append(w.handlers, func(g *gin.Context) {
g.Set("ginext.jsonfilter", filter)
})
return w
}
2023-07-18 14:40:10 +02:00
func (w *GinRouteBuilder) Handle(handler WHandlerFunc) {
2023-07-24 18:22:36 +02:00
2023-08-03 09:09:27 +02:00
if w.routes.wrapper.bufferBody {
2023-08-08 15:33:52 +02:00
arr := make([]gin.HandlerFunc, 0, len(w.handlers)+1)
2023-08-08 16:05:44 +02:00
arr = append(arr, BodyBuffer)
2023-08-03 09:09:27 +02:00
arr = append(arr, w.handlers...)
w.handlers = arr
}
2023-07-24 18:22:36 +02:00
middlewareNames := langext.ArrMap(w.handlers, func(v gin.HandlerFunc) string { return nameOfFunction(v) })
handlerName := nameOfFunction(handler)
2023-07-18 14:40:10 +02:00
w.handlers = append(w.handlers, Wrap(w.routes.wrapper, handler))
2023-07-24 18:22:36 +02:00
methodName := w.method
if w.method == "*" {
methodName = "ANY"
for _, method := range anyMethods {
w.routes.routes.Handle(method, w.relPath, w.handlers...)
}
} else {
w.routes.routes.Handle(w.method, w.relPath, w.handlers...)
2023-07-18 16:08:24 +02:00
}
2023-07-24 18:22:36 +02:00
w.routes.wrapper.routeSpecs = append(w.routes.wrapper.routeSpecs, ginRouteSpec{
Method: methodName,
2023-07-26 10:40:42 +02:00
URL: w.absPath,
2023-07-24 18:22:36 +02:00
Middlewares: middlewareNames,
Handler: handlerName,
})
2023-07-18 16:08:24 +02:00
}
func (w *GinWrapper) NoRoute(handler WHandlerFunc) {
2023-08-08 16:09:02 +02:00
handlers := make([]gin.HandlerFunc, 0)
if w.bufferBody {
handlers = append(handlers, BodyBuffer)
}
middlewareNames := langext.ArrMap(handlers, func(v gin.HandlerFunc) string { return nameOfFunction(v) })
handlerName := nameOfFunction(handler)
2023-08-08 16:10:31 +02:00
handlers = append(handlers, Wrap(w, handler))
2023-08-08 16:09:02 +02:00
w.engine.NoRoute(handlers...)
2023-07-24 18:22:36 +02:00
w.routeSpecs = append(w.routeSpecs, ginRouteSpec{
Method: "ANY",
URL: "[NO_ROUTE]",
2023-08-08 16:09:02 +02:00
Middlewares: middlewareNames,
Handler: handlerName,
2023-07-24 18:22:36 +02:00
})
}
func nameOfFunction(f any) string {
2023-07-24 18:42:33 +02:00
fname := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
2023-07-24 18:22:36 +02:00
2023-07-24 18:42:33 +02:00
split := strings.Split(fname, "/")
2023-07-24 18:22:36 +02:00
if len(split) == 0 {
return ""
}
2023-07-24 18:42:33 +02:00
fname = split[len(split)-1]
2023-07-24 18:47:48 +02:00
// https://stackoverflow.com/a/32925345/1761622
if strings.HasSuffix(fname, "-fm") {
fname = fname[:len(fname)-len("-fm")]
}
2023-07-26 10:44:26 +02:00
suffix := rext.W(regexp.MustCompile(`\.func[0-9]+(?:\.[0-9]+)*$`))
2023-07-24 18:50:14 +02:00
if match, ok := suffix.MatchFirst(fname); ok {
fname = fname[:len(fname)-match.FullMatch().Length()]
2023-07-24 18:42:33 +02:00
}
return fname
2023-07-18 14:40:10 +02:00
}
2023-07-25 11:16:11 +02:00
// joinPaths is copied verbatim from gin@v1.9.1/gin.go
func joinPaths(absolutePath, relativePath string) string {
if relativePath == "" {
return absolutePath
}
finalPath := path.Join(absolutePath, relativePath)
if lastChar(relativePath) == '/' && lastChar(finalPath) != '/' {
return finalPath + "/"
}
return finalPath
}
func lastChar(str string) uint8 {
if str == "" {
panic("The length of the string can't be 0")
}
return str[len(str)-1]
}