129 lines
3.5 KiB
Go
129 lines
3.5 KiB
Go
package serverimp
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/tech/sendico/notification/interface/api"
|
|
"github.com/tech/sendico/notification/interface/api/localizer"
|
|
apiimip "github.com/tech/sendico/notification/internal/api"
|
|
"github.com/tech/sendico/pkg/db"
|
|
"github.com/tech/sendico/pkg/mlogger"
|
|
"github.com/tech/sendico/pkg/mservice"
|
|
mduration "github.com/tech/sendico/pkg/mutil/duration"
|
|
"go.uber.org/zap"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type httpServerConf struct {
|
|
ListenAddress string `yaml:"listen_address"`
|
|
ReadHeaderTimeout int `yaml:"read_header_timeout"`
|
|
ShutdownTimeout int `yaml:"shutdown_timeout"`
|
|
}
|
|
|
|
// Config represents the server configuration
|
|
type Config struct {
|
|
API *api.Config `yaml:"api"`
|
|
DB *db.Config `yaml:"database"`
|
|
Localizer *localizer.Config `yaml:"localizer"`
|
|
HTTPServer *httpServerConf `yaml:"http_server"`
|
|
}
|
|
|
|
// Instance represents an instance of the server
|
|
type Imp struct {
|
|
logger mlogger.Logger
|
|
api mservice.MicroService
|
|
config *Config
|
|
db db.Factory
|
|
l localizer.Localizer
|
|
httpServer *http.Server
|
|
debug bool
|
|
file string
|
|
}
|
|
|
|
// Shutdown stops the server
|
|
func (i *Imp) Shutdown() {
|
|
// Shutdown HTTP server
|
|
ctx, cancel := context.WithTimeout(context.Background(), mduration.Param2Duration(i.config.HTTPServer.ShutdownTimeout, time.Second))
|
|
i.logger.Info("Shutting HTTP server down...")
|
|
if err := i.httpServer.Shutdown(ctx); err != nil {
|
|
if !errors.Is(err, http.ErrServerClosed) {
|
|
i.logger.Warn("Failed to shutdown HTTP server gracefully", zap.Error(err))
|
|
cancel()
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
cancel()
|
|
}
|
|
|
|
func (i *Imp) Run() error {
|
|
if err := i.httpServer.ListenAndServe(); err != nil {
|
|
if !errors.Is(err, http.ErrServerClosed) {
|
|
i.logger.Error("HTTP Server stopped unexpectedly", zap.Error(err))
|
|
}
|
|
}
|
|
i.logger.Info("HTTP Server stopped")
|
|
|
|
if err := i.api.Finish(context.Background()); err != nil {
|
|
i.logger.Warn("Error when finishing service", zap.Error(err))
|
|
}
|
|
|
|
i.db.CloseConnection()
|
|
|
|
return nil
|
|
}
|
|
|
|
// Start starts the server
|
|
func (i *Imp) Start() error {
|
|
i.logger.Info("Starting...", zap.String("config_file", i.file), zap.Bool("debug_mode", i.debug))
|
|
// Load configuration file
|
|
data, err := os.ReadFile(i.file)
|
|
if err != nil {
|
|
i.logger.Error("Could not load configuration", zap.Error(err), zap.String("config_file", i.file))
|
|
return err
|
|
}
|
|
|
|
if err = yaml.Unmarshal(data, &i.config); err != nil {
|
|
i.logger.Error("Failed to parse configuration", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if i.db, err = db.NewConnection(i.logger, i.config.DB); err != nil {
|
|
i.logger.Error("Could not open database connection", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if i.l, err = localizer.CreateLocalizer(i.logger, i.config.Localizer); err != nil {
|
|
i.logger.Error("Failed to create localizer", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
router := chi.NewRouter()
|
|
if i.api, err = apiimip.CreateAPI(i.logger, i.config.API, i.l, i.db, router, i.debug); err != nil {
|
|
i.logger.Error("Failed to create API instance", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
// Startup the HTTP Server in a way that we can gracefully shut it down again
|
|
i.httpServer = &http.Server{
|
|
Addr: i.config.HTTPServer.ListenAddress,
|
|
Handler: router,
|
|
ReadHeaderTimeout: mduration.Param2Duration(i.config.HTTPServer.ReadHeaderTimeout, time.Second),
|
|
}
|
|
|
|
return i.Run()
|
|
}
|
|
|
|
func Create(logger mlogger.Logger, file string, debug bool) (*Imp, error) {
|
|
srv := &Imp{
|
|
logger: logger,
|
|
debug: debug,
|
|
file: file,
|
|
}
|
|
return srv, nil
|
|
}
|