109 lines
2.4 KiB
Go
109 lines
2.4 KiB
Go
// ©AngelaMos | 2026
|
|
// server.go
|
|
|
|
package server
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
chimw "github.com/go-chi/chi/v5/middleware"
|
|
|
|
"github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/config"
|
|
"github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/health"
|
|
)
|
|
|
|
type Server struct {
|
|
httpServer *http.Server
|
|
router *chi.Mux
|
|
config config.ServerConfig
|
|
healthHandler *health.Handler
|
|
logger *slog.Logger
|
|
}
|
|
|
|
type Config struct {
|
|
ServerConfig config.ServerConfig
|
|
HealthHandler *health.Handler
|
|
Logger *slog.Logger
|
|
}
|
|
|
|
func New(cfg Config) *Server {
|
|
router := chi.NewRouter()
|
|
|
|
router.Use(chimw.CleanPath)
|
|
router.Use(chimw.StripSlashes)
|
|
|
|
return &Server{
|
|
httpServer: &http.Server{
|
|
Addr: cfg.ServerConfig.Address(),
|
|
Handler: router,
|
|
ReadTimeout: cfg.ServerConfig.ReadTimeout,
|
|
WriteTimeout: cfg.ServerConfig.WriteTimeout,
|
|
IdleTimeout: cfg.ServerConfig.IdleTimeout,
|
|
},
|
|
router: router,
|
|
config: cfg.ServerConfig,
|
|
healthHandler: cfg.HealthHandler,
|
|
logger: cfg.Logger,
|
|
}
|
|
}
|
|
|
|
func (s *Server) Router() *chi.Mux {
|
|
return s.router
|
|
}
|
|
|
|
func (s *Server) Start() error {
|
|
s.logger.Info("starting HTTP server",
|
|
"addr", s.config.Address(),
|
|
"read_timeout", s.config.ReadTimeout,
|
|
"write_timeout", s.config.WriteTimeout,
|
|
"idle_timeout", s.config.IdleTimeout,
|
|
)
|
|
|
|
if err := s.httpServer.ListenAndServe(); err != nil &&
|
|
!errors.Is(err, http.ErrServerClosed) {
|
|
return fmt.Errorf("http server error: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) Shutdown(ctx context.Context, drainDelay time.Duration) error {
|
|
s.logger.Info("initiating graceful shutdown")
|
|
|
|
s.logger.Info("marking server as not ready")
|
|
if s.healthHandler != nil {
|
|
s.healthHandler.SetReady(false)
|
|
s.healthHandler.SetShutdown(true)
|
|
}
|
|
|
|
s.logger.Info("waiting for load balancer to drain",
|
|
"delay", drainDelay,
|
|
)
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-time.After(drainDelay):
|
|
}
|
|
|
|
s.logger.Info("stopping HTTP server")
|
|
shutdownCtx, cancel := context.WithTimeout(ctx, s.config.ShutdownTimeout)
|
|
defer cancel()
|
|
|
|
if err := s.httpServer.Shutdown(shutdownCtx); err != nil {
|
|
return fmt.Errorf("http server shutdown: %w", err)
|
|
}
|
|
|
|
s.logger.Info("HTTP server stopped gracefully")
|
|
return nil
|
|
}
|
|
|
|
func (s *Server) Address() string {
|
|
return s.httpServer.Addr
|
|
}
|