clustvirt/router/server/server.go
2024-03-25 15:33:04 -06:00

99 lines
2.5 KiB
Go

package server
import (
"fmt"
"net/http"
"os"
"strings"
"time"
"git.staur.ca/stobbsm/clustvirt/cluster"
"git.staur.ca/stobbsm/clustvirt/lib/log"
"git.staur.ca/stobbsm/clustvirt/router"
"git.staur.ca/stobbsm/clustvirt/router/htmx"
"git.staur.ca/stobbsm/clustvirt/router/middleware"
)
// Server represents an HTTP server that uses net/http ServeMux to route requests
// Originally done with chi, but a migration to the new net/http patterns seems like
// a good choice to reduce dependencies, but does mean middleware needs to be implemented
// in the server
type Server struct {
bindAddr string
ssl bool
c *cluster.Cluster
middleware []middleware.Middleware
mux *http.ServeMux
}
// New creates a new HTTP Server instance.
// Requires the IP and port number to bind to
func New(listen string, port int, cluster *cluster.Cluster) *Server {
s := &Server{bindAddr: fmt.Sprintf("%s:%d", listen, port), c: cluster}
return s
}
// Start starts the server and initializes the router and common middleware
func (s *Server) Start() {
tstart := time.Now()
defer func() {
log.Info("router.Server.Start").
Dur("upTime", time.Since(tstart)).
Msg("http server stopped")
}()
s.mux = http.NewServeMux()
indev, _ := os.LookupEnv("CLUSTVIRT_DEV")
indev = strings.ToLower(indev)
switch indev {
case "true":
fallthrough
case "1":
fallthrough
case "yes":
fallthrough
case "on":
s.AddMiddleware(middleware.NoCache)
s.mux.Handle("GET /_/debug", middleware.Profiler())
}
s.AddMiddleware(middleware.Logger)
// Add routes
s.baseRoutes()
if err := s.AddSubRouter("/htmx", htmx.Htmx); err != nil {
log.Error("server.Start").
Str("subroute", "htmx").
Err(err).Send()
}
// Start the server
if err := http.ListenAndServe(s.bindAddr, s); err != nil {
log.Error("router.Server.Start").
Str("bindaddr", s.bindAddr).
Err(err).Send()
}
}
// AddMiddleware appends middleware to the chi router
func (s *Server) AddMiddleware(m ...middleware.Middleware) {
s.middleware = append(s.middleware, m...)
}
// AddSubRouter attachs a SubRouter using it's MountTo method. This method
// needs the path prefix and the defined routes
func (s *Server) AddSubRouter(pfx string, sr router.SubRouter) error {
return sr.MountTo(pfx, s.c, s.mux)
}
// ServeHTTP implements the Handler interface
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.chain().ServeHTTP(w, r)
}
func (s *Server) chain() http.Handler {
h := http.Handler(s.mux)
for i := range s.middleware {
h = s.middleware[len(s.middleware)-1-i](h)
}
return h
}