forked from ebhomengo/niki
122 lines
2.6 KiB
Go
122 lines
2.6 KiB
Go
package httpserver
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
echomiddleware "github.com/gocasters/rankr/pkg/echo_middleware"
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/labstack/echo/v4/middleware"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type Config struct {
|
|
Host string `koanf:"host"`
|
|
Port int `koanf:"port"`
|
|
CORS CORS `koanf:"cors"`
|
|
ShutdownTimeout time.Duration `koanf:"shutdown_context_timeout"`
|
|
HideBanner bool `koanf:"hide_banner"`
|
|
HidePort bool `koanf:"hide_port"`
|
|
PublicPaths []string `koanf:"public_paths"`
|
|
|
|
// Optional Otel middleware can be injected from outside.
|
|
OtelMiddleware echo.MiddlewareFunc
|
|
}
|
|
|
|
type CORS struct {
|
|
AllowOrigins []string `koanf:"allow_origins"`
|
|
}
|
|
|
|
type Server struct {
|
|
router *echo.Echo
|
|
config *Config
|
|
|
|
requireClaimsOnce sync.Once
|
|
}
|
|
|
|
var basePublicPaths = []string{
|
|
"/v1/login",
|
|
"/v1/refresh-token",
|
|
"/v1/me",
|
|
"/ping",
|
|
"/ping-otel",
|
|
}
|
|
|
|
func New(cfg Config) (*Server, error) {
|
|
if cfg.Port < 1 || cfg.Port > 65535 {
|
|
return nil, fmt.Errorf("invalid port: %d", cfg.Port)
|
|
}
|
|
|
|
if cfg.ShutdownTimeout <= 0 {
|
|
cfg.ShutdownTimeout = DefaultShutdownTimeout
|
|
}
|
|
|
|
e := echo.New()
|
|
|
|
if cfg.OtelMiddleware != nil {
|
|
e.Use(cfg.OtelMiddleware)
|
|
}
|
|
|
|
e.Use(middleware.RequestID())
|
|
e.Use(middleware.Logger())
|
|
e.Use(middleware.Recover())
|
|
e.Use(
|
|
middleware.CORSWithConfig(
|
|
middleware.CORSConfig{
|
|
AllowOrigins: cfg.CORS.AllowOrigins,
|
|
},
|
|
),
|
|
)
|
|
|
|
return &Server{
|
|
router: e,
|
|
config: &cfg,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) GetRouter() *echo.Echo {
|
|
s.requireClaimsOnce.Do(func() {
|
|
s.router.Use(
|
|
echomiddleware.RequireUserInfo(
|
|
echomiddleware.RequireUserInfoOptions{
|
|
Skipper: newPublicPathSkipper(s.config.PublicPaths...),
|
|
},
|
|
),
|
|
)
|
|
})
|
|
|
|
return s.router
|
|
}
|
|
|
|
func (s *Server) GetConfig() *Config {
|
|
return s.config
|
|
}
|
|
|
|
func (s *Server) Start() error {
|
|
addr := fmt.Sprintf("%s:%d", s.config.Host, s.config.Port)
|
|
|
|
s.router.HideBanner = s.config.HideBanner
|
|
s.router.HidePort = s.config.HidePort
|
|
|
|
return s.router.Start(addr)
|
|
}
|
|
|
|
func (s *Server) Stop(ctx context.Context) error {
|
|
return s.router.Shutdown(ctx)
|
|
}
|
|
|
|
func newPublicPathSkipper(extraPaths ...string) middleware.Skipper {
|
|
paths := make([]string, 0, len(basePublicPaths)+len(extraPaths))
|
|
paths = append(paths, basePublicPaths...)
|
|
paths = append(paths, extraPaths...)
|
|
staticPublicPathSkipper := echomiddleware.SkipExactPaths(paths...)
|
|
|
|
return func(c echo.Context) bool {
|
|
path := strings.TrimSuffix(c.Request().URL.Path, "/")
|
|
return staticPublicPathSkipper(c) ||
|
|
strings.HasSuffix(path, "/health-check") ||
|
|
strings.HasSuffix(path, "/health_check")
|
|
}
|
|
}
|