package httpsrv import ( "context" "log/slog" "net/http" "recipes/internal/config" "recipes/internal/http-server/handlers/recipe" recipeimage "recipes/internal/http-server/handlers/recipeImage" "recipes/internal/http-server/handlers/recipes" recipes_by_category "recipes/internal/http-server/handlers/recipesByCategory" mwLogger "recipes/internal/http-server/middleware/logger" "recipes/internal/lib/logger/sl" "time" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" ) type App struct { log *slog.Logger router *chi.Mux srv *http.Server } type Storage interface { recipe.RecipeProvider recipes.RecipesProvider recipes_by_category.RecipesProvider } type MediaStorage interface { recipeimage.ImageProvider } func New(log *slog.Logger, cfg *config.HTTPServerConfig, storage Storage, mediaStorage MediaStorage) *App { // init router router := chi.NewRouter() // middlewares router.Use(middleware.RequestID) router.Use(mwLogger.New(log)) router.Use(middleware.Recoverer) // routes router.Get("/recipe", recipe.New(log, storage)) router.Get("/recipes_page", recipes.New(log, storage)) router.Get("/recipes_by_category", recipes_by_category.New(log, storage)) router.Get("/recipe_img", recipeimage.New(log, mediaStorage)) // server config srv := &http.Server{ Addr: cfg.Address, Handler: router, ReadTimeout: cfg.Timeout, WriteTimeout: cfg.Timeout, IdleTimeout: cfg.IdleTimeout, } return &App{ log: log, router: router, srv: srv, } } // MustRun starts http server or panic in case of error. Blocking function. func (app *App) MustRun() { const op = "app.httpSrv.Stop" if err := app.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { app.log.Error("failed to start server", sl.Err(err)) panic(err) } app.log.Info("HTTP server stopped") } func (app *App) Stop() { const op = "app.httpSrv.Stop" shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second) err := app.srv.Shutdown(shutdownCtx) if err != nil { app.log.Error("failed to stop server", sl.Err(err)) } shutdownCancel() }