feat: add basic app
This commit is contained in:
parent
d4c1af4831
commit
c94098afef
13 changed files with 1850 additions and 0 deletions
114
internal/server/server.go
Normal file
114
internal/server/server.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
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
|
||||
}
|
||||
Reference in a new issue