package server import ( "context" "fmt" "net/http" "time" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/rs/zerolog" "github.com/vincentc-afk/gitea-notification-hub/internal/config" ) // Server represents the HTTP server type Server struct { cfg *config.Config logger zerolog.Logger router *chi.Mux srv *http.Server } // New creates a new Server instance func New(cfg *config.Config, logger zerolog.Logger) *Server { r := chi.NewRouter() // Middleware r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Recoverer) r.Use(requestLogger(logger)) s := &Server{ cfg: cfg, logger: logger, router: r, } // Health check endpoint r.Get("/health", s.handleHealth) return s } // Router returns the chi router for registering additional routes func (s *Server) Router() *chi.Mux { return s.router } // Start starts the HTTP server func (s *Server) Start() error { addr := fmt.Sprintf(":%d", s.cfg.Server.Port) s.srv = &http.Server{ Addr: addr, Handler: s.router, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, IdleTimeout: 60 * time.Second, } s.logger.Info().Str("addr", addr).Msg("starting HTTP server") return s.srv.ListenAndServe() } // Shutdown gracefully shuts down the server func (s *Server) Shutdown(ctx context.Context) error { s.logger.Info().Msg("shutting down HTTP server") return s.srv.Shutdown(ctx) } func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write([]byte(`{"status":"ok"}`)) } // requestLogger returns a middleware that logs HTTP requests func requestLogger(logger zerolog.Logger) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor) defer func() { logger.Info(). Str("method", r.Method). Str("path", r.URL.Path). Int("status", ww.Status()). Dur("duration", time.Since(start)). Msg("request") }() next.ServeHTTP(ww, r) }) } }