package web import ( "context" "errors" "fmt" "net/http" "time" ) type ServerConfig struct { Host string Port int ReadHeaderTimeout time.Duration ShutdownTimeout time.Duration } func Run(ctx context.Context, cfg ServerConfig, handler http.Handler) error { server := &http.Server{ Addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), Handler: handler, ReadHeaderTimeout: cfg.ReadHeaderTimeout, } serveErr := make(chan error, 1) go func() { serveErr <- server.ListenAndServe() }() select { case err := <-serveErr: if errors.Is(err, http.ErrServerClosed) { return nil } return fmt.Errorf("serve explorer: %w", err) case <-ctx.Done(): } shutdownCtx, cancel := context.WithTimeout(context.Background(), cfg.ShutdownTimeout) defer cancel() if err := server.Shutdown(shutdownCtx); err != nil { _ = server.Close() return fmt.Errorf("shut down explorer: %w", err) } err := <-serveErr if err != nil && !errors.Is(err, http.ErrServerClosed) { return fmt.Errorf("serve explorer: %w", err) } return nil }