1
0
Fork 0
This repository has been archived on 2025-08-23. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
mareshq-backoffice-v3-api/internal/server/server.go

114 lines
3.1 KiB
Go

package server
import (
"context"
"errors"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
oapimiddleware "github.com/oapi-codegen/nethttp-middleware"
"gitlab.mareshq.com/hq/backoffice/backoffice-api/internal/training"
"log"
"net/http"
"time"
)
type Server struct {
logger *log.Logger
hostname string
trainingRepository training.Repository
router *chi.Mux
srv *http.Server
tls *TLS
}
type TLS struct {
CertFile string
KeyFile string
}
func NewServer(hostname string, logger *log.Logger, trainingRepository training.Repository) *Server {
return &Server{
logger: logger,
hostname: hostname,
trainingRepository: trainingRepository,
router: chi.NewRouter(),
tls: nil,
}
}
func NewServerWithTLS(hostname string, tls *TLS, logger *log.Logger, trainingRepository training.Repository) *Server {
s := NewServer(hostname, logger, trainingRepository)
s.tls = tls
return s
}
func (s *Server) Run(ctx context.Context) error {
swagger, err := GetSwagger()
if err != nil {
return err
}
// Clear out the servers array in the swagger spec, that skips validating
// that server names match. We don't know how this thing will be run.
swagger.Servers = nil
s.router.Use(middleware.Logger)
// middleware.Recoverer recovers from panics, logs the panic (and a stack trace),
s.router.Use(middleware.Recoverer)
// we trust headers, since we are running on Kubernetes with Ingress Controller (Ingress-NGINX)
// and behind an L4 load balancer (on Hetzner Cloud)
s.router.Use(middleware.RealIP)
// middleware.RequestID generates a request ID and adds it to request context
// if the request has an `X-Request-ID` header, it will use that as the request ID
s.router.Use(middleware.RequestID)
s.router.Use(middleware.Timeout(10 * time.Second))
s.router.Use(oapimiddleware.OapiRequestValidator(swagger))
// create handler
h := NewStrictHandler(s, nil)
// register endpoints
HandlerFromMux(h, s.router)
s.srv = &http.Server{
Addr: ":8080", // TODO: make port configurable
Handler: s.router,
}
go func() {
var err error
if s.tls != nil {
s.logger.Printf("Starting HTTPS server on: %s\n", s.srv.Addr)
err = s.srv.ListenAndServeTLS(s.tls.CertFile, s.tls.KeyFile)
} else {
s.logger.Printf("Starting HTTP server on: %s\n", s.srv.Addr)
err = s.srv.ListenAndServe()
}
// suppress the error if the server was closed gracefully
if err != nil && !errors.Is(err, http.ErrServerClosed) {
s.logger.Printf("error: %v\n", err)
}
}()
// wait for the context to be done
// context done means the server is shutting down
<-ctx.Done()
// TODO: make graceful shutdown period configurable
timeout := 10 * time.Second
timeoutCtx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
s.logger.Printf("Shutting down server in %s seconds\n", timeout.String())
err = s.srv.Shutdown(timeoutCtx)
// suppress the error if the server was closed gracefully
if err != nil && !errors.Is(err, http.ErrServerClosed) {
return err
}
s.logger.Println("Server shutdown successfully")
return nil
}