2024-03-24 04:05:06 +00:00
|
|
|
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"
|
|
|
|
)
|
|
|
|
|
2024-03-24 05:59:56 +00:00
|
|
|
// 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
|
2024-03-24 04:05:06 +00:00
|
|
|
type Server struct {
|
2024-03-24 05:59:56 +00:00
|
|
|
bindAddr string
|
|
|
|
ssl bool
|
|
|
|
c *cluster.Cluster
|
|
|
|
middleware []middleware.Middleware
|
|
|
|
mux *http.ServeMux
|
2024-03-24 04:05:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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")
|
|
|
|
}()
|
2024-03-24 05:59:56 +00:00
|
|
|
s.mux = http.NewServeMux()
|
2024-03-24 04:05:06 +00:00
|
|
|
|
|
|
|
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)
|
2024-03-24 05:59:56 +00:00
|
|
|
s.mux.Handle("GET /_/debug", middleware.Profiler())
|
2024-03-24 04:05:06 +00:00
|
|
|
}
|
2024-03-24 05:59:56 +00:00
|
|
|
s.AddMiddleware(middleware.Logger)
|
2024-03-24 04:05:06 +00:00
|
|
|
// Add routes
|
|
|
|
s.baseRoutes()
|
2024-03-25 01:38:46 +00:00
|
|
|
if err := s.AddSubRouter("/htmx", htmx.Htmx); err != nil {
|
2024-03-24 04:05:06 +00:00
|
|
|
log.Error("server.Start").
|
|
|
|
Str("subroute", "htmx").
|
|
|
|
Err(err).Send()
|
|
|
|
}
|
|
|
|
// Start the server
|
2024-03-24 05:59:56 +00:00
|
|
|
if err := http.ListenAndServe(s.bindAddr, s); err != nil {
|
2024-03-24 04:05:06 +00:00
|
|
|
log.Error("router.Server.Start").
|
|
|
|
Str("bindaddr", s.bindAddr).
|
|
|
|
Err(err).Send()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddMiddleware appends middleware to the chi router
|
2024-03-24 05:59:56 +00:00
|
|
|
func (s *Server) AddMiddleware(m ...middleware.Middleware) {
|
|
|
|
s.middleware = append(s.middleware, m...)
|
2024-03-24 04:05:06 +00:00
|
|
|
}
|
|
|
|
|
2024-03-25 01:38:46 +00:00
|
|
|
// 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)
|
2024-03-24 05:59:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2024-03-24 04:05:06 +00:00
|
|
|
}
|