github.com/shoshinnikita/budget-manager@v0.7.1-0.20220131195411-8c46ff1c6778/internal/web/web.go (about)

     1  package web
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/ShoshinNikita/budget-manager/internal/logger"
    10  	"github.com/ShoshinNikita/budget-manager/internal/pkg/errors"
    11  	"github.com/ShoshinNikita/budget-manager/internal/web/api"
    12  	"github.com/ShoshinNikita/budget-manager/internal/web/middlewares"
    13  	"github.com/ShoshinNikita/budget-manager/internal/web/pages"
    14  	"github.com/ShoshinNikita/budget-manager/static"
    15  )
    16  
    17  type Server struct {
    18  	config Config
    19  	log    logger.Logger
    20  	db     Database
    21  
    22  	server *http.Server
    23  
    24  	version string
    25  	gitHash string
    26  }
    27  
    28  type Database interface {
    29  	api.DB
    30  	pages.DB
    31  }
    32  
    33  func NewServer(cfg Config, db Database, log logger.Logger, version, gitHash string) *Server {
    34  	s := &Server{
    35  		config: cfg,
    36  		db:     db,
    37  		log:    log,
    38  		//
    39  		version: version,
    40  		gitHash: gitHash,
    41  	}
    42  	s.server = &http.Server{
    43  		Addr:    ":" + strconv.Itoa(cfg.Port),
    44  		Handler: s.buildServerHandler(),
    45  	}
    46  
    47  	return s
    48  }
    49  
    50  func (s *Server) buildServerHandler() http.Handler {
    51  	router := http.NewServeMux()
    52  
    53  	if !s.config.UseEmbed {
    54  		s.log.Warn("don't use embedded templates and static files")
    55  	}
    56  
    57  	// Add API routes
    58  	s.addRoutes(router)
    59  	if s.config.EnableProfiling {
    60  		// Enable pprof handlers
    61  		s.log.Warn("pprof handlers are enabled")
    62  		s.addPprofRoutes(router)
    63  	}
    64  
    65  	// Add File Handler
    66  	fs := http.FS(static.New(s.config.UseEmbed))
    67  	fileHandler := http.StripPrefix("/static/", http.FileServer(fs))
    68  	fileHandler = middlewares.CachingMiddleware(fileHandler, time.Hour*24*30, s.gitHash) // cache for 1 month
    69  	router.Handle("/static/", fileHandler)
    70  
    71  	// Wrap the handler in middlewares. The last middleware will be called first and so on
    72  	var handler http.Handler = router
    73  	if !s.config.Auth.Disable {
    74  		handler = middlewares.BasicAuthMiddleware(handler, s.config.Auth.BasicAuthCreds, s.log)
    75  		if len(s.config.Auth.BasicAuthCreds) == 0 {
    76  			s.log.Warn("auth is enabled, but list of creds is empty")
    77  		}
    78  	} else {
    79  		s.log.Warn("auth is disabled")
    80  	}
    81  	handler = middlewares.LoggingMiddleware(handler, s.log)
    82  	handler = middlewares.RequestIDMeddleware(handler)
    83  
    84  	return handler
    85  }
    86  
    87  func (s Server) ListenAndServer() error {
    88  	s.log.Debug("start server")
    89  
    90  	if err := s.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
    91  		return errors.Wrap(err, "server error")
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  func (s Server) Shutdown() error {
    98  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    99  	defer cancel()
   100  
   101  	return s.server.Shutdown(ctx)
   102  }