metricator/internal/httpserver/httpserver.go

98 lines
2.7 KiB
Go
Raw Normal View History

2020-11-28 23:34:20 +05:00
package httpserver
import (
"context"
"net"
"net/http"
"strings"
"time"
"go.dev.pztrn.name/metricator/internal/common"
2020-11-28 23:34:20 +05:00
"go.dev.pztrn.name/metricator/internal/configuration"
2020-12-23 16:28:57 +05:00
"go.dev.pztrn.name/metricator/internal/logger"
2020-11-28 23:34:20 +05:00
)
// HTTPServer is a controlling structure for HTTP server.
type HTTPServer struct {
config *configuration.Config
ctx context.Context
doneChan chan struct{}
2020-12-23 16:28:57 +05:00
logger *logger.Logger
2020-11-28 23:34:20 +05:00
handler *handler
server *http.Server
}
2020-12-23 20:55:50 +05:00
// NewHTTPServer creates HTTP server and executes preliminary initialization
// (HTTP server structure initialized but it doesn't start).
2020-12-23 16:28:57 +05:00
func NewHTTPServer(ctx context.Context, cfg *configuration.Config, logger *logger.Logger) (*HTTPServer, chan struct{}) {
2021-11-21 14:45:09 +05:00
// nolint:exhaustivestruct
httpServer := &HTTPServer{
2020-11-28 23:34:20 +05:00
config: cfg,
ctx: ctx,
doneChan: make(chan struct{}),
2020-12-23 16:28:57 +05:00
logger: logger,
2020-11-28 23:34:20 +05:00
}
2021-11-21 14:45:09 +05:00
httpServer.initialize()
2020-11-28 23:34:20 +05:00
2021-11-21 14:45:09 +05:00
return httpServer, httpServer.doneChan
2020-11-28 23:34:20 +05:00
}
// Returns request's context based on main context of application.
// Basically it returns main context and does nothing more.
func (h *HTTPServer) getRequestContext(_ net.Listener) context.Context {
return h.ctx
}
// Initializes handler and HTTP server structure.
func (h *HTTPServer) initialize() {
2020-12-23 16:28:57 +05:00
h.logger.Debugln("Initializing HTTP server...")
h.handler = &handler{
handlers: make(map[string]common.HTTPHandlerFunc),
}
// We do not need to specify all possible parameters for HTTP server, so:
2020-11-29 05:52:52 +05:00
// nolint:exhaustivestruct
2020-11-28 23:34:20 +05:00
h.server = &http.Server{
// ToDo: make it all configurable.
Addr: ":34421",
BaseContext: h.getRequestContext,
Handler: h.handler,
ReadTimeout: time.Second * 10,
WriteTimeout: time.Second * 10,
MaxHeaderBytes: 1 << 20,
}
}
// RegisterHandlerForApplication registers HTTP handler for application.
func (h *HTTPServer) RegisterHandlerForApplication(name string, handler common.HTTPHandlerFunc) {
2020-12-23 16:28:57 +05:00
h.logger.Debugln("Registering handler for application", name)
h.handler.register(name, handler)
}
2020-11-28 23:34:20 +05:00
// Start starts HTTP server in another goroutine and one more goroutine which
// is listening to main context's Cancel() call to stop HTTP server.
func (h *HTTPServer) Start() {
go func() {
err := h.server.ListenAndServe()
if err != nil {
if !strings.Contains(err.Error(), "Server closed") {
2020-12-23 16:28:57 +05:00
h.logger.Infoln("HTTP server failed to listen:", err.Error())
2020-11-28 23:34:20 +05:00
}
}
}()
go func() {
<-h.ctx.Done()
2020-12-23 16:28:57 +05:00
h.logger.Infoln("Shutting down HTTP server")
2020-11-28 23:34:20 +05:00
err := h.server.Shutdown(h.ctx)
if err != nil && !strings.Contains(err.Error(), "context canceled") {
2020-12-23 16:28:57 +05:00
h.logger.Infoln("Failed to stop HTTP server:", err.Error())
2020-11-28 23:34:20 +05:00
}
2020-12-23 16:28:57 +05:00
h.logger.Infoln("HTTP server stopped")
2020-11-28 23:34:20 +05:00
h.doneChan <- struct{}{}
}()
}