diff --git a/ginext/engine.go b/ginext/engine.go index 771905f..9447eb6 100644 --- a/ginext/engine.go +++ b/ginext/engine.go @@ -1,8 +1,12 @@ package ginext import ( + "fmt" "github.com/gin-gonic/gin" + "gogs.mikescher.com/BlackForestBytes/goext/langext" + "gogs.mikescher.com/BlackForestBytes/goext/mathext" "net/http" + "strings" "time" ) @@ -13,6 +17,15 @@ type GinWrapper struct { allowCors bool ginDebug bool requestTimeout time.Duration + + routeSpecs []ginRouteSpec +} + +type ginRouteSpec struct { + Method string + URL string + Middlewares []string + Handler string } func NewEngine(allowCors bool, ginDebug bool, timeout time.Duration) *GinWrapper { @@ -33,18 +46,63 @@ func NewEngine(allowCors bool, ginDebug bool, timeout time.Duration) *GinWrapper engine.Use(CorsMiddleware()) } + // do not debug-print routes + gin.DebugPrintRouteFunc = func(_, _, _ string, _ int) {} + if ginDebug { + gin.SetMode(gin.ReleaseMode) + ginlogger := gin.Logger() engine.Use(func(context *gin.Context) { if !wrapper.SuppressGinLogs { ginlogger(context) } }) + } else { + gin.SetMode(gin.DebugMode) } return wrapper } func (w *GinWrapper) ServeHTTP(writer http.ResponseWriter, request *http.Request) { + + if w.ginDebug { + w.debugPrintRoutes() + } + w.engine.ServeHTTP(writer, request) } + +func (w *GinWrapper) debugPrintRoutes() { + + lines := make([][4]string, 0) + + pad := [4]int{0, 0, 0, 0} + + for _, spec := range w.routeSpecs { + + line := [4]string{ + spec.Method, + spec.URL, + strings.Join(spec.Middlewares, " --> "), + spec.Method, + } + + lines = append(lines, line) + + pad[0] = mathext.Max(pad[0], len(line[0])) + pad[1] = mathext.Max(pad[1], len(line[1])) + pad[2] = mathext.Max(pad[2], len(line[2])) + pad[3] = mathext.Max(pad[3], len(line[3])) + } + + for _, line := range lines { + + fmt.Printf("Gin-Route: [%s] @ %s --> %s --> %s", + langext.StrPadRight(line[0], " ", pad[0]), + langext.StrPadRight(line[1], " ", pad[1]), + langext.StrPadRight(line[2], " ", pad[2]), + langext.StrPadRight(line[3], " ", pad[3])) + } +} diff --git a/ginext/routes.go b/ginext/routes.go index a698c63..e82af85 100644 --- a/ginext/routes.go +++ b/ginext/routes.go @@ -4,6 +4,9 @@ import ( "github.com/gin-gonic/gin" "gogs.mikescher.com/BlackForestBytes/goext/langext" "net/http" + "reflect" + "runtime" + "strings" ) var anyMethods = []string{ @@ -21,7 +24,7 @@ type GinRoutesWrapper struct { type GinRouteBuilder struct { routes *GinRoutesWrapper - methods []string + method string relPath string handlers []gin.HandlerFunc } @@ -41,39 +44,39 @@ func (w *GinRoutesWrapper) Use(middleware ...gin.HandlerFunc) *GinRoutesWrapper } func (w *GinRoutesWrapper) GET(relativePath string) *GinRouteBuilder { - return &GinRouteBuilder{routes: w, methods: []string{http.MethodGet}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} + return &GinRouteBuilder{routes: w, method: http.MethodGet, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} } func (w *GinRoutesWrapper) POST(relativePath string) *GinRouteBuilder { - return &GinRouteBuilder{routes: w, methods: []string{http.MethodPost}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} + return &GinRouteBuilder{routes: w, method: http.MethodPost, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} } func (w *GinRoutesWrapper) DELETE(relativePath string) *GinRouteBuilder { - return &GinRouteBuilder{routes: w, methods: []string{http.MethodDelete}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} + return &GinRouteBuilder{routes: w, method: http.MethodDelete, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} } func (w *GinRoutesWrapper) PATCH(relativePath string) *GinRouteBuilder { - return &GinRouteBuilder{routes: w, methods: []string{http.MethodPatch}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} + return &GinRouteBuilder{routes: w, method: http.MethodPatch, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} } func (w *GinRoutesWrapper) PUT(relativePath string) *GinRouteBuilder { - return &GinRouteBuilder{routes: w, methods: []string{http.MethodPut}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} + return &GinRouteBuilder{routes: w, method: http.MethodPut, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} } func (w *GinRoutesWrapper) OPTIONS(relativePath string) *GinRouteBuilder { - return &GinRouteBuilder{routes: w, methods: []string{http.MethodOptions}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} + return &GinRouteBuilder{routes: w, method: http.MethodOptions, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} } func (w *GinRoutesWrapper) HEAD(relativePath string) *GinRouteBuilder { - return &GinRouteBuilder{routes: w, methods: []string{http.MethodHead}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} + return &GinRouteBuilder{routes: w, method: http.MethodHead, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} } func (w *GinRoutesWrapper) COUNT(relativePath string) *GinRouteBuilder { - return &GinRouteBuilder{routes: w, methods: []string{"COUNT"}, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} + return &GinRouteBuilder{routes: w, method: "COUNT", relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} } func (w *GinRoutesWrapper) Any(relativePath string) *GinRouteBuilder { - return &GinRouteBuilder{routes: w, methods: anyMethods, relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} + return &GinRouteBuilder{routes: w, method: "*", relPath: relativePath, handlers: langext.ArrCopy(w.defaultHandler)} } func (w *GinRouteBuilder) Use(middleware ...gin.HandlerFunc) *GinRouteBuilder { @@ -82,12 +85,50 @@ func (w *GinRouteBuilder) Use(middleware ...gin.HandlerFunc) *GinRouteBuilder { } func (w *GinRouteBuilder) Handle(handler WHandlerFunc) { + + middlewareNames := langext.ArrMap(w.handlers, func(v gin.HandlerFunc) string { return nameOfFunction(v) }) + handlerName := nameOfFunction(handler) + w.handlers = append(w.handlers, Wrap(w.routes.wrapper, handler)) - for _, m := range w.methods { - w.routes.routes.Handle(m, w.relPath, w.handlers...) + + 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...) } + + w.routes.wrapper.routeSpecs = append(w.routes.wrapper.routeSpecs, ginRouteSpec{ + Method: methodName, + URL: w.relPath, + Middlewares: middlewareNames, + Handler: handlerName, + }) } func (w *GinWrapper) NoRoute(handler WHandlerFunc) { w.engine.NoRoute(Wrap(w, handler)) + + w.routeSpecs = append(w.routeSpecs, ginRouteSpec{ + Method: "ANY", + URL: "[NO_ROUTE]", + Middlewares: nil, + Handler: nameOfFunction(handler), + }) +} + +func nameOfFunction(f any) string { + + n := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name() + + split := strings.Split(n, "/") + if len(split) == 0 { + return "" + } + + return split[len(split)-1] } diff --git a/goextVersion.go b/goextVersion.go index 70cbce7..a92d9d5 100644 --- a/goextVersion.go +++ b/goextVersion.go @@ -1,5 +1,5 @@ package goext -const GoextVersion = "0.0.200" +const GoextVersion = "0.0.201" -const GoextVersionTimestamp = "2023-07-24T17:42:18+0200" +const GoextVersionTimestamp = "2023-07-24T18:22:36+0200"