Files
sendico/api/notification/internal/server/internal/serverimp.go
Stephan D d367dddbbd
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
fx build fix
2025-11-08 00:40:01 +01:00

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
}