goext/ginext/engine.go

150 lines
3.2 KiB
Go
Raw Permalink Normal View History

2023-07-18 14:40:10 +02:00
package ginext
2023-07-18 15:12:06 +02:00
import (
2023-07-24 18:22:36 +02:00
"fmt"
2023-07-18 15:12:06 +02:00
"github.com/gin-gonic/gin"
2023-07-24 18:34:56 +02:00
"github.com/rs/zerolog/log"
2023-07-24 18:22:36 +02:00
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/mathext"
2023-07-24 18:34:56 +02:00
"net"
2023-07-18 16:01:34 +02:00
"net/http"
2023-07-24 18:22:36 +02:00
"strings"
2023-07-18 15:12:06 +02:00
"time"
)
2023-07-18 14:40:10 +02:00
type GinWrapper struct {
engine *gin.Engine
SuppressGinLogs bool
2023-07-24 11:11:15 +02:00
allowCors bool
ginDebug bool
2023-08-03 09:09:27 +02:00
bufferBody bool
2023-07-24 11:11:15 +02:00
requestTimeout time.Duration
2023-07-24 18:22:36 +02:00
routeSpecs []ginRouteSpec
}
type ginRouteSpec struct {
Method string
URL string
Middlewares []string
Handler string
2023-07-18 14:40:10 +02:00
}
2023-08-03 09:09:27 +02:00
// NewEngine creates a new (wrapped) ginEngine
// Parameters are:
// - [allowCors] Add cors handler to allow all CORS requests on the default http methods
// - [ginDebug] Set gin.debug to true (adds more logs)
// - [bufferBody] Buffers the input body stream, this way the ginext error handler can later include the whole request body
// - [timeout] The default handler timeout
func NewEngine(allowCors bool, ginDebug bool, bufferBody bool, timeout time.Duration) *GinWrapper {
2023-07-18 14:40:10 +02:00
engine := gin.New()
wrapper := &GinWrapper{
engine: engine,
SuppressGinLogs: false,
allowCors: allowCors,
ginDebug: ginDebug,
2023-08-03 09:09:27 +02:00
bufferBody: bufferBody,
2023-07-18 15:12:06 +02:00
requestTimeout: timeout,
2023-07-18 14:40:10 +02:00
}
engine.RedirectFixedPath = false
engine.RedirectTrailingSlash = false
if allowCors {
engine.Use(CorsMiddleware())
}
2023-07-24 18:22:36 +02:00
// do not debug-print routes
gin.DebugPrintRouteFunc = func(_, _, _ string, _ int) {}
2023-07-18 14:40:10 +02:00
if ginDebug {
2023-07-24 18:22:36 +02:00
gin.SetMode(gin.ReleaseMode)
2023-07-18 14:40:10 +02:00
ginlogger := gin.Logger()
engine.Use(func(context *gin.Context) {
if !wrapper.SuppressGinLogs {
ginlogger(context)
}
})
2023-07-24 18:22:36 +02:00
} else {
gin.SetMode(gin.DebugMode)
2023-07-18 14:40:10 +02:00
}
return wrapper
}
2023-07-18 16:01:34 +02:00
2023-07-24 18:34:56 +02:00
func (w *GinWrapper) ListenAndServeHTTP(addr string, postInit func(port string)) (chan error, *http.Server) {
2023-07-24 18:38:04 +02:00
w.DebugPrintRoutes()
2023-07-24 18:34:56 +02:00
httpserver := &http.Server{
Addr: addr,
Handler: w.engine,
2023-07-24 18:22:36 +02:00
}
2023-07-24 18:34:56 +02:00
errChan := make(chan error)
go func() {
ln, err := net.Listen("tcp", httpserver.Addr)
if err != nil {
errChan <- err
return
}
_, port, err := net.SplitHostPort(ln.Addr().String())
if err != nil {
errChan <- err
return
}
log.Info().Str("address", httpserver.Addr).Msg("HTTP-Server started on http://localhost:" + port)
if postInit != nil {
2023-07-24 18:38:04 +02:00
postInit(port) // the net.Listener a few lines above is at this point actually already buffering requests
2023-07-24 18:34:56 +02:00
}
errChan <- httpserver.Serve(ln)
}()
return errChan, httpserver
2023-07-18 16:01:34 +02:00
}
2023-07-24 18:22:36 +02:00
2023-07-24 18:34:56 +02:00
func (w *GinWrapper) DebugPrintRoutes() {
if !w.ginDebug {
return
}
2023-07-24 18:22:36 +02:00
lines := make([][4]string, 0)
pad := [4]int{0, 0, 0, 0}
for _, spec := range w.routeSpecs {
line := [4]string{
spec.Method,
spec.URL,
2023-07-24 18:42:33 +02:00
strings.Join(spec.Middlewares, " -> "),
spec.Handler,
2023-07-24 18:22:36 +02:00
}
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 {
2023-07-24 18:42:33 +02:00
fmt.Printf("Gin-Route: %s %s --> %s --> %s\n",
langext.StrPadRight("["+line[0]+"]", " ", pad[0]+2),
2023-07-24 18:22:36 +02:00
langext.StrPadRight(line[1], " ", pad[1]),
langext.StrPadRight(line[2], " ", pad[2]),
langext.StrPadRight(line[3], " ", pad[3]))
}
}