weather/internal/web/server.go

117 lines
2.9 KiB
Go
Raw Normal View History

package web
import (
"context"
"crypto/tls"
"fmt"
"go/weather/internal"
"go/weather/internal/storage"
"go/weather/pkg/headers"
"go/weather/pkg/logger"
"net"
"net/http"
"os"
"time"
"github.com/gorilla/mux"
"go.uber.org/zap"
)
const (
apiPrefix = "/api"
apiRouterName = "api"
)
//WeatherServer http server for weather application
type WeatherServer struct {
http.Server
router *mux.Router
wlogger *logger.WeatherLogger
whandler *WeatherHandler
version string
}
//New construct new instance
2021-03-01 23:53:22 +00:00
func New(logger *logger.WeatherLogger, addr ListenAddr, version string) *WeatherServer {
return &WeatherServer{
Server: http.Server{
Addr: addr.String(),
BaseContext: func(l net.Listener) context.Context {
return context.Background()
},
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
},
router: mux.NewRouter(),
wlogger: logger,
version: version,
}
}
//WithHandler register weather handler
func (ws *WeatherServer) WithHandler(config *internal.WeatherConfig) *WeatherServer {
storage := storage.NewS3Storage(ws.wlogger, &config.S3Storage)
ws.whandler = NewWeatherHandler(ws.wlogger, storage, ws.router)
// register each subrouter
ws.whandler.RegisterBase()
ws.whandler.RegisterApi(ws.version)
return ws
}
//WithHTTPLogging add http server request/response logging capability
func (ws *WeatherServer) WithHTTPLogging() *WeatherServer {
ws.Server.Handler = ws.wlogger.HTTPLogHandler(ws.router)
api := ws.whandler.GetOrCreateSubRouterByName(apiRouterName, apiPrefix)
api.HandleFunc("/log", func(rw http.ResponseWriter, r *http.Request) {
rw.Header().Add(headers.ContentType, "application/json")
ws.wlogger.Level.ServeHTTP(rw, r)
})
return ws
}
//WithErrorLogging add http server error logging capability
func (ws *WeatherServer) WithErrorLogging() *WeatherServer {
stdLogger, err := zap.NewStdLogAt(ws.wlogger.Logger, zap.ErrorLevel)
ws.handleError(err)
ws.Server.ErrorLog = stdLogger
return ws
}
//WithTLSConfigure add cert and key file to server, permit TLS capability
func (ws *WeatherServer) WithTLSConfigure() *WeatherServer {
currentPath, err := os.Getwd()
ws.handleError(err)
certPath := fmt.Sprintf("%s%ccerts%cout%cweather.pem", currentPath, os.PathSeparator, os.PathSeparator, os.PathSeparator)
keyPath := fmt.Sprintf("%s%ccerts%cout%cweather-key.pem", currentPath, os.PathSeparator, os.PathSeparator, os.PathSeparator)
cert, err := tls.LoadX509KeyPair(
certPath,
keyPath,
)
ws.handleError(err)
ws.Server.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
return ws
}
//Serve start http server
func (ws *WeatherServer) Serve() error {
// Server.Hanlder is nil when we don't use WithHTTPLogging
if ws.Server.Handler == nil {
ws.Server.Handler = ws.router
}
return ws.Server.ListenAndServeTLS("", "")
}
//handleError generic fatal error
func (ws *WeatherServer) handleError(err error) {
if err != nil {
ws.wlogger.Fatal("Server error", zap.Error(err))
}
}