package app import ( "context" "errors" "go.uber.org/zap" "gitea.pena/PenaSide/tariffs/internal/controller/middleware" "gitea.pena/PenaSide/tariffs/internal/initialize" "gitea.pena/PenaSide/tariffs/internal/models" "gitea.pena/PenaSide/tariffs/internal/server/http" "gitea.pena/PenaSide/tariffs/pkg/closer" "time" ) func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger) error { defer func() { if r := recover(); r != nil { logger.Error("Recovered from a panic", zap.Any("error", r)) } }() logger.Info("Starting application", zap.Any("AppCFG", cfg)) ctx, cancel := context.WithCancel(ctx) defer cancel() shutdownGroup := closer.NewCloserGroup() mdb, err := initialize.MongoDB(ctx, cfg) if err != nil { logger.Error("Failed to initialize MongoDB", zap.Error(err)) return err } mw := middleware.NewMiddleware(logger) repositories := initialize.NewRepository(initialize.RepositoryDeps{ Logger: logger, Mdb: mdb, }) controllers := initialize.NewControllers(initialize.ControllerDeps{ Logger: logger, Repos: repositories, MW: mw, }) internalSrv := http.NewServer(http.ServerConfig{ Logger: logger, Controllers: []http.Controller{controllers.PrivilegeInternal, controllers.TariffInternal}, JWTConfig: &models.JWTConfiguration{ PrivateKey: cfg.PrivateKey, PublicKey: cfg.PublicKey, Issuer: cfg.Issuer, Audience: cfg.Audience, }, }) externalSrv := http.NewServer(http.ServerConfig{ Logger: logger, Controllers: []http.Controller{controllers.PrivilegeExternal, controllers.TariffExternal}, JWTConfig: &models.JWTConfiguration{ PrivateKey: cfg.PrivateKey, PublicKey: cfg.PublicKey, Issuer: cfg.Issuer, Audience: cfg.Audience, }, }) go func() { if err := internalSrv.Start(cfg.InternalHttpAddress); err != nil { logger.Error("Server startup error", zap.Error(err)) cancel() } }() go func() { if err := externalSrv.Start(cfg.ExternalHttpAddress); err != nil { logger.Error("Server startup error", zap.Error(err)) cancel() } }() internalSrv.ListRoutes() externalSrv.ListRoutes() shutdownGroup.Add(closer.CloserFunc(internalSrv.Shutdown)) shutdownGroup.Add(closer.CloserFunc(externalSrv.Shutdown)) shutdownGroup.Add(closer.CloserFunc(mdb.Client().Disconnect)) <-ctx.Done() timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), 10*time.Second) defer timeoutCancel() if err := shutdownGroup.Call(timeoutCtx); err != nil { if errors.Is(err, context.DeadlineExceeded) { logger.Error("Shutdown timed out", zap.Error(err)) } else { logger.Error("Failed to shutdown services gracefully", zap.Error(err)) } return err } logger.Info("Application has stopped") return nil }