WIP: sneak/next #21

Draft
sneak wants to merge 6 commits from sneak/next into master
5 changed files with 55 additions and 23 deletions
Showing only changes of commit 46b67f8a6e - Show all commits

View File

@ -20,10 +20,10 @@ func (s *Handlers) handleHealthCheck() http.HandlerFunc {
Status: "ok", Status: "ok",
Now: time.Now().UTC().Format(time.RFC3339Nano), Now: time.Now().UTC().Format(time.RFC3339Nano),
UptimeSeconds: int64(s.uptime().Seconds()), UptimeSeconds: int64(s.uptime().Seconds()),
UptimeHuman: s.uptime().String(), UptimeHuman: s.params.Server.uptime().String(),
Maintenance: s.maintenance(), Maintenance: s.params.Server.MaintenanceMode(),
Appname: s.appname, Appname: s.params.Globals.Appname,
Version: s.version, Version: s.params.Globals.Version,
} }
s.respondJSON(w, req, resp, 200) s.respondJSON(w, req, resp, 200)
} }

View File

@ -1,19 +1,43 @@
package server package middleware
import ( import (
"net" "net"
"net/http" "net/http"
"time" "time"
"git.eeqj.de/sneak/gohttpserver/internal/config"
"git.eeqj.de/sneak/gohttpserver/internal/globals"
"git.eeqj.de/sneak/gohttpserver/internal/logger"
basicauth "github.com/99designs/basicauth-go" basicauth "github.com/99designs/basicauth-go"
"github.com/go-chi/chi/middleware" "github.com/go-chi/chi/middleware"
"github.com/go-chi/cors" "github.com/go-chi/cors"
"github.com/rs/zerolog"
metrics "github.com/slok/go-http-metrics/metrics/prometheus" metrics "github.com/slok/go-http-metrics/metrics/prometheus"
ghmm "github.com/slok/go-http-metrics/middleware" ghmm "github.com/slok/go-http-metrics/middleware"
"github.com/slok/go-http-metrics/middleware/std" "github.com/slok/go-http-metrics/middleware/std"
"github.com/spf13/viper" "github.com/spf13/viper"
"go.uber.org/fx"
) )
type MiddlewareParams struct {
fx.In
Logger logger.Logger
Globals globals.Globals
Config config.Config
}
type Middleware struct {
log *zerolog.Logger
params MiddlewareParams
}
func New(lc fx.Lifecycle, params MiddlewareParams) (*Middleware, error) {
s := new(Middleware)
s.params = params
s.log = params.Logger.Get()
return s, nil
}
// the following is from // the following is from
// https://learning-cloud-native-go.github.io/docs/a6.adding_zerolog_logger/ // https://learning-cloud-native-go.github.io/docs/a6.adding_zerolog_logger/
@ -45,7 +69,7 @@ func (lrw *loggingResponseWriter) WriteHeader(code int) {
// type Middleware func(http.Handler) http.Handler // type Middleware func(http.Handler) http.Handler
// this returns a Middleware that is designed to do every request through the // this returns a Middleware that is designed to do every request through the
// mux, note the signature: // mux, note the signature:
func (s *Server) LoggingMiddleware() func(http.Handler) http.Handler { func (s *Middleware) LoggingMiddleware() func(http.Handler) http.Handler {
// FIXME this should use https://github.com/google/go-cloud/blob/master/server/requestlog/requestlog.go // FIXME this should use https://github.com/google/go-cloud/blob/master/server/requestlog/requestlog.go
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -73,7 +97,7 @@ func (s *Server) LoggingMiddleware() func(http.Handler) http.Handler {
} }
} }
func (s *Server) CORSMiddleware() func(http.Handler) http.Handler { func (s *Middleware) CORSMiddleware() func(http.Handler) http.Handler {
return cors.Handler(cors.Options{ return cors.Handler(cors.Options{
// CHANGEME! these are defaults, change them to suit your needs or // CHANGEME! these are defaults, change them to suit your needs or
// read from environment/viper. // read from environment/viper.
@ -88,7 +112,7 @@ func (s *Server) CORSMiddleware() func(http.Handler) http.Handler {
}) })
} }
func (s *Server) AuthMiddleware() func(http.Handler) http.Handler { func (s *Middleware) AuthMiddleware() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// CHANGEME you'll want to change this to do stuff. // CHANGEME you'll want to change this to do stuff.
@ -98,7 +122,7 @@ func (s *Server) AuthMiddleware() func(http.Handler) http.Handler {
} }
} }
func (s *Server) MetricsMiddleware() func(http.Handler) http.Handler { func (s *Middleware) MetricsMiddleware() func(http.Handler) http.Handler {
mdlw := ghmm.New(ghmm.Config{ mdlw := ghmm.New(ghmm.Config{
Recorder: metrics.NewRecorder(metrics.Config{}), Recorder: metrics.NewRecorder(metrics.Config{}),
}) })
@ -107,7 +131,7 @@ func (s *Server) MetricsMiddleware() func(http.Handler) http.Handler {
} }
} }
func (s *Server) MetricsAuthMiddleware() func(http.Handler) http.Handler { func (s *Middleware) MetricsAuthMiddleware() func(http.Handler) http.Handler {
return basicauth.New( return basicauth.New(
"metrics", "metrics",
map[string][]string{ map[string][]string{

View File

@ -18,7 +18,7 @@ func (s *Server) serveUntilShutdown() {
// add routes // add routes
// this does any necessary setup in each handler // this does any necessary setup in each handler
s.routes() s.SetupRoutes()
s.log.Info().Str("listenaddr", listenAddr).Msg("http begin listen") s.log.Info().Str("listenaddr", listenAddr).Msg("http begin listen")
if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {

View File

@ -23,16 +23,16 @@ func (s *Server) SetupRoutes() {
s.router.Use(middleware.Recoverer) s.router.Use(middleware.Recoverer)
s.router.Use(middleware.RequestID) s.router.Use(middleware.RequestID)
s.router.Use(s.LoggingMiddleware()) s.router.Use(s.mw.LoggingMiddleware())
// add metrics middleware only if we can serve them behind auth // add metrics middleware only if we can serve them behind auth
if viper.GetString("METRICS_USERNAME") != "" { if viper.GetString("METRICS_USERNAME") != "" {
s.router.Use(s.MetricsMiddleware()) s.router.Use(s.mw.MetricsMiddleware())
} }
// set up CORS headers. you'll probably want to configure that // set up CORS headers. you'll probably want to configure that
// in middlewares.go. // in middlewares.go.
s.router.Use(s.CORSMiddleware()) s.router.Use(s.mw.CORSMiddleware())
// CHANGEME to suit your needs, or pull from config. // CHANGEME to suit your needs, or pull from config.
// timeout for request context; your handlers must finish within // timeout for request context; your handlers must finish within
@ -57,12 +57,12 @@ func (s *Server) SetupRoutes() {
// complete docs: https://github.com/go-chi/chi // complete docs: https://github.com/go-chi/chi
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
s.router.Get("/", s.handleIndex()) s.router.Get("/", s.h.handleIndex())
s.router.Mount("/s", http.StripPrefix("/s", http.FileServer(http.FS(static.Static)))) s.router.Mount("/s", http.StripPrefix("/s", http.FileServer(http.FS(static.Static))))
s.router.Route("/api/v1", func(r chi.Router) { s.router.Route("/api/v1", func(r chi.Router) {
r.Get("/now", s.handleNow()) r.Get("/now", s.h.handleNow())
}) })
// if you want to use a general purpose middleware (http.Handler // if you want to use a general purpose middleware (http.Handler
@ -71,25 +71,25 @@ func (s *Server) SetupRoutes() {
authMiddleware := s.AuthMiddleware() authMiddleware := s.AuthMiddleware()
s.router.Get( s.router.Get(
"/login", "/login",
authMiddleware(s.handleLogin()).ServeHTTP, authMiddleware(s.h.handleLogin()).ServeHTTP,
) )
// route that panics for testing // route that panics for testing
// CHANGEME remove this // CHANGEME remove this
s.router.Get( s.router.Get(
"/panic", "/panic",
s.handlePanic(), s.h.handlePanic(),
) )
s.router.Get( s.router.Get(
"/.well-known/healthcheck.json", "/.well-known/healthcheck.json",
s.handleHealthCheck(), s.h.handleHealthCheck(),
) )
// set up authenticated /metrics route: // set up authenticated /metrics route:
if viper.GetString("METRICS_USERNAME") != "" { if viper.GetString("METRICS_USERNAME") != "" {
s.router.Group(func(r chi.Router) { s.router.Group(func(r chi.Router) {
r.Use(s.MetricsAuthMiddleware()) r.Use(s.mw.MetricsAuthMiddleware())
r.Get("/metrics", http.HandlerFunc(promhttp.Handler().ServeHTTP)) r.Get("/metrics", http.HandlerFunc(promhttp.Handler().ServeHTTP))
}) })
} }

View File

@ -12,7 +12,9 @@ import (
"git.eeqj.de/sneak/gohttpserver/internal/config" "git.eeqj.de/sneak/gohttpserver/internal/config"
"git.eeqj.de/sneak/gohttpserver/internal/globals" "git.eeqj.de/sneak/gohttpserver/internal/globals"
"git.eeqj.de/sneak/gohttpserver/internal/handlers"
"git.eeqj.de/sneak/gohttpserver/internal/logger" "git.eeqj.de/sneak/gohttpserver/internal/logger"
"git.eeqj.de/sneak/gohttpserver/internal/middleware"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/spf13/viper" "github.com/spf13/viper"
"go.uber.org/fx" "go.uber.org/fx"
@ -35,6 +37,8 @@ type ServerParams struct {
Logger logger.Logger Logger logger.Logger
Globals globals.Globals Globals globals.Globals
Config config.Config Config config.Config
Middleware middleware.Middleware
Handlers handlers.Handlers
} }
type Server struct { type Server struct {
@ -51,11 +55,15 @@ type Server struct {
httpServer *http.Server httpServer *http.Server
router *chi.Mux router *chi.Mux
params ServerParams params ServerParams
mw middleware.Middleware
h handlers.Handlers
} }
func New(lc fx.Lifecycle, params ServerParams) (*Server, error) { func New(lc fx.Lifecycle, params ServerParams) (*Server, error) {
s := new(Server) s := new(Server)
s.params = params s.params = params
s.mw = params.Middleware
s.h = params.Handlers
s.log = params.Logger.Get() s.log = params.Logger.Get()
lc.Append(fx.Hook{ lc.Append(fx.Hook{